

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.ico">
  <link rel="icon" href="/img/favicon.ico">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="叶尘的技术升级小木屋">
  <meta name="author" content="叶尘">
  <meta name="keywords" content="">
  
  <title>Spring - 叶尘的技术升级小木屋</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10.7.2/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->

  
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/shubiao.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/gundongtiao.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/daziyanse.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/toubudaziji.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.yechen-blog.cn","root":"/","version":"1.8.11","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>YECHEN</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-qrcode"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/playlist/">
                <i class="iconfont icon-music"></i>
                音乐
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" target="_self" role="button"
                 data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="iconfont icon-books"></i>
                链接
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/">
                    
                    主题博客
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/guide/">
                    
                    配置指南
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/icon/">
                    
                    图标用法
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://www.bilibili.com">
                    
                    哔哩哔哩
                  </a>
                
              </div>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/banner.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Spring">
              
            </span>

            
              <div class="mt-3">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-author" aria-hidden="true"></i>
      叶尘
    </span>
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-09-13 17:44" pubdate>
        星期一, 九月 13日 2021, 5:44 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      20.2k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      279
       分钟
    </span>
  

  
  
    
      <!-- LeanCloud 统计文章PV -->
      <span id="leancloud-page-views-container" class="post-meta" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="leancloud-page-views"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Spring</h1>
            
            <div class="markdown-body">
              <h2 id="1-Spring-概述"><a href="#1-Spring-概述" class="headerlink" title="1. Spring 概述"></a>1. Spring 概述</h2><h3 id="Spring-简介"><a href="#Spring-简介" class="headerlink" title="Spring 简介"></a>Spring 简介</h3><p>Spring 是一个开源框架，是一个与 2003 年兴起的<strong>轻量级的 Java 开发框架</strong>，最早由<strong>Rod Johnson</strong>创建，目的是为了解决企业级应用开发的业务逻辑层和其他各层的<strong>耦合问题</strong>。它是一个分层的 JavaSE/JavaEE full-stack（一站式）轻量级开源框架，为开发 Java 应用程序提供全面的基础架构支持。Spring 负责基础架构，因此 Java 开发者可以专注于应用程序的开发。Spring 最根本的使命是<strong>解决企业级应用开发的复杂性，即简化 Java 开发</strong>。</p>
<p><strong>Spring的核心是控制反转（IoC）和面向切面编程（AOP）</strong></p>
<h3 id="Spring-由那些模块构成？"><a href="#Spring-由那些模块构成？" class="headerlink" title="Spring 由那些模块构成？"></a>Spring 由那些模块构成？</h3><p>Spring 总共大约有 20 个模块， 由 1300 多个不同的文件构成。 而这些组件被分别整合在==核心容器（Core Container）== 、 ==AOP（Aspect Oriented Programming）==和==设备支持（Instrmentation）== 、==数据访问与集成（Data Access/Integeration）== 、==Web==、 ==消息（Messaging）== 、 ==测试（Test）== 等 6 个模块中。 以下是 Spring 5 的模块结构图：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.5qfahkg992o0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li><strong>spring core</strong>：提供了框架的基本组成部分，包括控制反转（Inversion of Control，IOC）和依赖注入（Dependency Injection，DI）功能。</li>
<li><strong>spring beans</strong>：提供了BeanFactory，是工厂模式的一个经典实现，Spring 将管理对象称为 Bean。</li>
<li><strong>spring context</strong>：构建于 core 封装包基础上的 context 封装包，提供了一种框架式的对象访问方法。</li>
<li><strong>spring jdbc</strong>：提供了一个JDBC的抽象层，消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析， 用于简化 JDBC。</li>
<li><strong>spring aop</strong>：提供了面向切面的编程实现，让你可以自定义拦截器、切点等。</li>
<li><strong>spring web</strong>：提供了针对 Web 开发的集成特性，例如文件上传，利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。</li>
<li><strong>spring test</strong>：主要为测试提供支持的，支持使用 JUnit 或 TestNG 对 Spring 组件进行单元测试和集成测试。</li>
</ul>
<h2 id="2-Spring-的控制反转-Ioc"><a href="#2-Spring-的控制反转-Ioc" class="headerlink" title="2. Spring 的控制反转(Ioc)"></a>2. Spring 的控制反转(Ioc)</h2><p>控制反转即 IoC (Inversion of Control)，它把传统上由程序代码直接<strong>操控的对象的调用权交给容器</strong>，通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移，从程序代码本身转移到了外部容器。</p>
<p>Spring Ioc 的实现方法是通过<strong>依赖注入 DI（Dependency Injection）</strong>，即在程序运行过程中，若需要调用另一个对象协助时，无须在代码中创建被调用者，而是依赖于外部容器，由外部容器创建后传递给程序。</p>
<p>Spring 的依赖注入对调用者与被调用者几乎没有任何要求，完全支持对象之间依赖关系的管理。</p>
<blockquote>
<p>Spring 容器是一个超级大工厂，负责创建、管理所有的 Java 对象，这些 Java 对象被称为 Bean。Spring 容器管理着容器中 Bean 之间的依赖关系，Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。</p>
</blockquote>
<h3 id="2-1-简单使用-Spring-Ioc"><a href="#2-1-简单使用-Spring-Ioc" class="headerlink" title="2.1  简单使用 Spring Ioc"></a>2.1  简单使用 Spring Ioc</h3><ol>
<li>创建一个接口类（SomeService.java）</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> cn.yechen.service;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">SomeService</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span></span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="2">
<li>创建一个接口实现类（SomeServiceImpl.java），并实现 doSome 方法</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> cn.yechen.service.impl;<br><br><span class="hljs-keyword">import</span> cn.yechen.service.SomeService;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SomeServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">SomeService</span> </span>&#123;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SomeServiceImpl</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;执行了 SomeServiceImpl 的无参数构造方法&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;执行了 SomeService 的 doSome() 方法&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="3">
<li>在 resources 目录下新建 Spring 的配置文件（applictionContext.xml）</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">    Spring 的配置文件</span><br><span class="hljs-comment">    1. beans：是根标签，Spring 中把 java 对象称为 bean</span><br><span class="hljs-comment">    2. spring-beans.xsd：是约束文件</span><br><span class="hljs-comment">--&gt;</span><br><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">       http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">        Spring 要创建某个类的对象，需要声明 bean</span><br><span class="hljs-comment">        &lt;bean class=&quot;&quot; id=&quot;&quot;/&gt;</span><br><span class="hljs-comment">        class：类的全限定名称，不能是接口（因为 Spring 使用反射机制创建对象）</span><br><span class="hljs-comment">        id：自定义变量名，代表对象，Spring 通过这个名称找到对象</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">        Spring 会将创建好后的对象存放到容器内部的一个 map 中</span><br><span class="hljs-comment">        key 是 id 的值，即对象名称，</span><br><span class="hljs-comment">        value 是指生成的对象</span><br><span class="hljs-comment">        即执行语句：</span><br><span class="hljs-comment">			springMap.put(&quot;someService&quot;, new SomeServiceImpl());</span><br><span class="hljs-comment">        之后通过 key 取 value，就可以拿到生成的对象了</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">        一个 bean 标签生成一个 java 对象</span><br><span class="hljs-comment">    --&gt;</span>    <br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.service.impl.SomeServiceImpl&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;someService&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.service.impl.SomeServiceImpl&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;someService1&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">        使用 Spring 创建一个非自定义的已存在的对象</span><br><span class="hljs-comment">     --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;java.util.Date&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;nowTime&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="4">
<li>测试使用（AppTest.java）</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> cn.yechen;<br><br><span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> org.junit.Assert.assertTrue;<br><br><span class="hljs-keyword">import</span> cn.yechen.service.SomeService;<br><span class="hljs-keyword">import</span> cn.yechen.service.impl.SomeServiceImpl;<br><span class="hljs-keyword">import</span> org.junit.Test;<br><span class="hljs-keyword">import</span> org.springframework.context.ApplicationContext;<br><span class="hljs-keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test02</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-comment">// 1. 指定 Spring 配置文件的路径</span><br>        String config = <span class="hljs-string">&quot;applicationContext.xml&quot;</span>;<br>        <span class="hljs-comment">// 2. 创建表示 Spring 容器的对象</span><br>        ApplicationContext applicationContext = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(config);<br>        <span class="hljs-comment">// 3. 调用对象方法通过 id，从容器中获取对象</span><br>        SomeService someService = (SomeService) applicationContext.getBean(<span class="hljs-string">&quot;someService&quot;</span>);<br>        someService.doSome();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>发现：通过 debug 发现 bean 指定实例创建时机是 执行 <code>getBean()</code> 方法的时候</strong></p>
<h3 id="2-2-基于-XML-的DI"><a href="#2-2-基于-XML-的DI" class="headerlink" title="2.2  基于 XML 的DI"></a>2.2  基于 XML 的DI</h3><p>bean 实例在调用无参构造器创建对象后，就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的，称为注入。</p>
<p>根据注入方式的不同，常用的有两类：<strong>构造注入、set 注入</strong>。</p>
<h4 id="2-2-1-构造注入"><a href="#2-2-1-构造注入" class="headerlink" title="2.2.1  构造注入"></a>2.2.1  构造注入</h4><p>Spring 通过调用类的有参数构造方法，在创建对象的同时，在构造方法中给属性赋值构造注入使用标签 &lt;constructor-arg&gt;，一个 &lt;constructor-arg&gt; 表示构造方法的一个参数</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;java.io.File&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;file&quot;</span> &gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">constructor-arg</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;parent&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;C:\Users\30117\Desktop\Spring学习&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">constructor-arg</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;child&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;beans.xml&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>属性有：</p>
<ul>
<li>name：表示构造方法的形参名</li>
<li>index：表示构造方法的参数的位置，参数从左往右位置是 0，1，2… 的顺序</li>
<li>value：构造方法的形参类型是简单类型的，使用 value</li>
<li>ref：构造方法的形参类型是引用类型的，使用 ref</li>
</ul>
<p>name 和 index 属性可以任选其一，在赋值顺序与构造方法中变量顺序一致时，可以省略 index</p>
<h4 id="2-2-2-通过-set-注入（设值注入）"><a href="#2-2-2-通过-set-注入（设值注入）" class="headerlink" title="2.2.2  通过 set 注入（设值注入）"></a>2.2.2  通过 set 注入（设值注入）</h4><p>即 Spring 先调用类的无参构造方法创建对象，再调用类的 set 方法，通过 set 方法完成属性的赋值</p>
<ul>
<li><strong>简单类型的 set 注入：</strong></li>
</ul>
<p>简单类型：Spring 中规定 java 中的基本数据类型，包括包装类，以及 String，都是简单类型</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!--  一个 &lt;property&gt;只能给一个属性赋值 --&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;属性名称&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;给属性赋的值&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>【注意】：</p>
<p> 对于使用 set 注入赋值的类，一定要存在对应的 set 方法，否则会抛出异常。</p>
<p>对于 set 方法存在，但属性不存在情况，运行时不会出现异常，因为 Spring 只是去执行对应的 set 方法,有没有对应属性是不管的。因此可以理解，&lt;property&gt;  标签中的 name 属性只是一个标志，Spring 根据命名规则通过标志来寻找对应的 set 方法的，然后执行该方法。</p>
<ul>
<li><strong>引用数据类型的 set 注入：</strong>                          </li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;&quot;</span>&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;属性名称&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;bean标签的id（对象名称）&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ul>
<li><strong>其他类型的 set 注入（数组，list，map，set，null，配置文件）</strong></li>
</ul>
<p>首先编写一个实体类 Student.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 此处省略 set 方法 和 toString 方法，但是一定要写</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> Address address;<br>    <span class="hljs-keyword">private</span> String[] booksName;<br>    <span class="hljs-keyword">private</span> List&lt;String&gt; hobbies;<br>    <span class="hljs-keyword">private</span> Map&lt;String, String&gt; course;<br>    <span class="hljs-keyword">private</span> Set&lt;String&gt; games;<br>    <span class="hljs-keyword">private</span> Properties info;<br>    <span class="hljs-keyword">private</span> String wife;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>spring 配置文件 applicationContext.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;address&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Address&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;city&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;绍兴&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;stress&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;上虞小越&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;student&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Student&quot;</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 普通值注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;叶尘&quot;</span>/&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- bean 注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;address&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;address&quot;</span>/&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- 数组注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;booksName&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">array</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>西游记<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>红楼梦<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>水浒传<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>三国演义<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">array</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- list 集合注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;hobbies&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">list</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>唱<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>跳<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>rap<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">list</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- map 集合注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;course&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">map</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">entry</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;语文&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;110&quot;</span>/&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">entry</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;数学&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;130&quot;</span>/&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">entry</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;英语&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;125&quot;</span>/&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">map</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- set 集合注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;games&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">set</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>LOL<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>COC<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span>BOB<span class="hljs-tag">&lt;/<span class="hljs-name">value</span>&gt;</span><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">set</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- null 值注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;wife&quot;</span>&gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">null</span>/&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>        <span class="hljs-comment">&lt;!-- 配置文件注入 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;info&quot;</span> &gt;</span><br>            <span class="hljs-tag">&lt;<span class="hljs-name">props</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;学号&quot;</span>&gt;</span>A001<span class="hljs-tag">&lt;/<span class="hljs-name">prop</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;性别&quot;</span>&gt;</span>男<span class="hljs-tag">&lt;/<span class="hljs-name">prop</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;班级&quot;</span>&gt;</span>高一三班<span class="hljs-tag">&lt;/<span class="hljs-name">prop</span>&gt;</span><br>                <span class="hljs-tag">&lt;<span class="hljs-name">prop</span> <span class="hljs-attr">key</span>=<span class="hljs-string">&quot;班主任&quot;</span>&gt;</span>小明<span class="hljs-tag">&lt;/<span class="hljs-name">prop</span>&gt;</span><br><br>            <span class="hljs-tag">&lt;/<span class="hljs-name">props</span>&gt;</span><br>        <span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试类 MyTest.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        Student student = (Student) context.getBean(<span class="hljs-string">&quot;student&quot;</span>);<br>        System.out.println(student);<br>        <span class="hljs-comment">/*</span><br><span class="hljs-comment">         输出：</span><br><span class="hljs-comment">         Student&#123;</span><br><span class="hljs-comment">             name=&#x27;叶尘&#x27;,</span><br><span class="hljs-comment">             address=Address&#123;city=&#x27;绍兴&#x27;, stress=&#x27;上虞小越&#x27;&#125;,</span><br><span class="hljs-comment">             booksName=[西游记, 红楼梦, 水浒传, 三国演义],</span><br><span class="hljs-comment">             hobbies=[唱, 跳, rap],</span><br><span class="hljs-comment">             course=&#123;语文=110, 数学=130, 英语=125&#125;,</span><br><span class="hljs-comment">             games=[LOL, COC, BOB],</span><br><span class="hljs-comment">             info=&#123;班主任=小明, 班级=高一三班, 学号=A001, 性别=男&#125;,</span><br><span class="hljs-comment">             wife=&#x27;null&#x27;</span><br><span class="hljs-comment">         &#125;</span><br><span class="hljs-comment">        */</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-2-3-p-命名空间注入、c-命名空间注入（扩展方式注入）"><a href="#2-2-3-p-命名空间注入、c-命名空间注入（扩展方式注入）" class="headerlink" title="2.2.3  p 命名空间注入、c 命名空间注入（扩展方式注入）"></a>2.2.3  p 命名空间注入、c 命名空间注入（扩展方式注入）</h4><p>实体类 User.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 要写 setter 和 构造方法</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>spring 配置文件 userbeans.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:p</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/p&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:c</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/c&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">        首先要引入 xmlns:p=&quot;http://www.springframework.org/schema/p&quot;</span><br><span class="hljs-comment">        p 命名空间的注入，可以直接注入属性的值，p 是 property 的简称</span><br><span class="hljs-comment">        其本质还是 set 注入</span><br><span class="hljs-comment">    --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.User&quot;</span> <span class="hljs-attr">p:name</span>=<span class="hljs-string">&quot;yechen&quot;</span> <span class="hljs-attr">p:age</span>=<span class="hljs-string">&quot;18&quot;</span>/&gt;</span><br><br>    <span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">        首先要引入 xmlns:c=&quot;http://www.springframework.org/schema/c&quot;</span><br><span class="hljs-comment">        c 命名空间的注入，本质是使用构造方法注入，c 是  constructor 的简称</span><br><span class="hljs-comment">    --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user2&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.User&quot;</span> <span class="hljs-attr">c:name</span>=<span class="hljs-string">&quot;zhangsan&quot;</span> <span class="hljs-attr">c:age</span>=<span class="hljs-string">&quot;19&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testUser</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;userBeans.xml&quot;</span>);<br>    <span class="hljs-comment">// 这里可以对 getBeans 方法添加第二参数，指定从容器中获取对象的类型，这样就可以不用强转了</span><br>    User user = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    System.out.println(user);<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>注意点：p 命名空间和 c 命名空间不能直接使用，需要导入 xml 约束</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs xml">xmlns:p=&quot;http://www.springframework.org/schema/p&quot;<br>xmlns:c=&quot;http://www.springframework.org/schema/c&quot;<br></code></pre></td></tr></table></figure>



<h2 id="3-bean-的作用域"><a href="#3-bean-的作用域" class="headerlink" title="3.  bean 的作用域"></a>3.  bean 的作用域</h2><p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210710/image.7by6pemzz6s0.png" srcset="/img/loading.gif" lazyload alt="image">        </p>
<h3 id="3-1-Singleton（单例模式，默认机制）"><a href="#3-1-Singleton（单例模式，默认机制）" class="headerlink" title="3.1 Singleton（单例模式，默认机制）"></a>3.1 Singleton（单例模式，默认机制）</h3><p>在 spring 容器中只创建 bean 定义的对象的一个实例，当从容器中多次获取实例时，获取到了总是同一个。</p>
<p>实例创建的时机是加载配置文件的时候，即 <code>ApplicationContext context = new ClassPathXmlApplicationContext(&quot;配置文件&quot;);</code></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210710/image.300r4e7q2i60.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>验证：</strong></p>
<p>实体类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 要写上 setter</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;<br><br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;调用了 User 的无参构造方法&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>使用 p 命名空间创建一个 bean</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 默认就是单例，所有也可以不写 scope=&quot;singleton&quot;--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.User&quot;</span> <span class="hljs-attr">p:name</span>=<span class="hljs-string">&quot;yechen&quot;</span> <span class="hljs-attr">p:age</span>=<span class="hljs-string">&quot;18&quot;</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">&quot;singleton&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testSingleton</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;userBeans.xml&quot;</span>);<br>    User user = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    User user2 = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    System.out.println(user == user2);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果：只调用了一个构造方法，从容器中获取到的两个对象是同一个。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.2vapf1qolws0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="3-2-Prototype（原型模式）"><a href="#3-2-Prototype（原型模式）" class="headerlink" title="3.2 Prototype（原型模式）"></a>3.2 Prototype（原型模式）</h3><p>每当 bean 被注入到另一个 bean 中，或者通过<code>getBean()</code>容器上的方法调用来获取 bean 的时候都会创建一个 bean 实例。</p>
<p>创建实例的时机不是在加载 spring 配置文件时候，是在调用 <code>getBean()</code> 方法时候创建多实例对象。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.f5423tyh6r4.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>测试：</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.User&quot;</span> <span class="hljs-attr">p:name</span>=<span class="hljs-string">&quot;yechen&quot;</span> <span class="hljs-attr">p:age</span>=<span class="hljs-string">&quot;18&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;user2&quot;</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">&quot;prototype&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testPrototype</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;userBeans.xml&quot;</span>);<br>    User user = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    User user2 = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    System.out.println(user == user2);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试结果：在 getBean() 方法执行的时候，都会创建一个新的 User 实例。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.5a8s0nokeow0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="3-3-其余的模式"><a href="#3-3-其余的模式" class="headerlink" title="3.3 其余的模式"></a>3.3 其余的模式</h3><p><code>request</code>、<code>session</code>、<code>application</code>、<code>webSocket</code> 只能在 <strong>Web</strong> 开发中使用，这里不详细了解。</p>
<h2 id="4-bean-的自动装配"><a href="#4-bean-的自动装配" class="headerlink" title="4. bean 的自动装配"></a>4. bean 的自动装配</h2><p>自动装配是 Spring 满足 bean 依赖的一种方式，Spring 会在上下文中自动寻找并自动给 bean 装配属性！</p>
<p>在 Spring 中有三种装配的方式：</p>
<ol>
<li>在 xml 文件中显式地配置（之前就是）。</li>
<li>在 java 文件中显式地配置（之后再讲）。</li>
<li>隐式的自动装配 bean（就在这里）。</li>
</ol>
<p>测试环境：</p>
<p>实体类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">shout</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;喵喵喵！&quot;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">shout</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;汪汪汪！&quot;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 存在 setter</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> Cat cat;<br>    <span class="hljs-keyword">private</span> Dog dog;<br>    <span class="hljs-keyword">private</span> String name;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="4-1-使用-XML-实现自动装配"><a href="#4-1-使用-XML-实现自动装配" class="headerlink" title="4.1 使用 XML 实现自动装配"></a>4.1 使用 XML 实现自动装配</h3><h4 id="4-1-1-byName-自动装配"><a href="#4-1-1-byName-自动装配" class="headerlink" title="4.1.1 byName 自动装配"></a>4.1.1 byName 自动装配</h4><p>Spring 会自动在容器上下文中查找和当前 bean 中需要装配的属性同名（即同 id）的 bean，并自动装配。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;cat&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Cat&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dog111&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Dog&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;people&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.People&quot;</span> <span class="hljs-attr">autowire</span>=<span class="hljs-string">&quot;byName&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;叶尘&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>使用条件：</strong>装配进去的 bean 要和属性==同名同类型==</p>
<p><strong>弊端：</strong>当不存在同名 bean 或者同名 bean 的类型与需要装配的属性的类型不一致时，自动装配会出现问题。</p>
<h4 id="4-1-2-byType-自动装配"><a href="#4-1-2-byType-自动装配" class="headerlink" title="4.1.2 byType 自动装配"></a>4.1.2 byType 自动装配</h4><p>Spring 会自动在容器上下文中查找和当前 bean 中需要装配的属性同类型（即同 class）的 bean，并自动装配。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;cat&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Cat&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dog111&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Dog&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;people&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.People&quot;</span> <span class="hljs-attr">autowire</span>=<span class="hljs-string">&quot;byType&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;叶尘&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>使用条件：</strong>装配进去的 bean 要和属性==同类型==</p>
<p><strong>弊端：</strong>当有多个类型（class）一致的 bean 时，通过属性自动装配就会出现问题</p>
<h3 id="4-2-使用注解实现自动装配"><a href="#4-2-使用注解实现自动装配" class="headerlink" title="4.2 使用注解实现自动装配"></a>4.2 使用注解实现自动装配</h3><p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.7gdi1c112c00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210709/image.6k15wryxllw0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<blockquote>
<p>如果想要使用注解自动装配，需要现在配置文件中<strong>导入约束（context 约束），并配置注解的支持</strong></p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">    <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">    <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">    <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">context:annotation-config</span>/&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>



<h4 id="4-2-1-Autowired-注解"><a href="#4-2-1-Autowired-注解" class="headerlink" title="4.2.1 @Autowired 注解"></a>4.2.1 @Autowired 注解</h4><p><code>@Autowired</code> 注释，它可以对类<strong>成员变量、方法及构造函数</strong>进行标注，完成自动装配的工作。 通过 @Autowired的使用来消除 set ，get方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span> </span>&#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> Cat cat;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> Dog dog;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">People</span><span class="hljs-params">(Cat cat, Dog dog)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.cat = cat;<br>        <span class="hljs-keyword">this</span>.dog = dog;<br>    &#125;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">play</span><span class="hljs-params">(Cat cat, Dog dog)</span> </span>&#123;<br>        cat.shout();<br>        dog.shout();<br>    &#125;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setCat</span><span class="hljs-params">(Cat cat)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.cat = cat;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><code>@Autowired</code> 注解 在默认情况下是在 Ioc 容器中根据类型匹配（<code>byType</code>）注入，当存在多个类型相同的 bean 时，才会根据名称匹配注入（<code>byName</code>）。</p>
<p>==<strong>优先级：byType —&gt;  byName —&gt;  Qualifier</strong>==</p>
<p>在 <code>@Autowired</code> 注解中存在一个<code>required</code>属性，默认为 true，当一个注入点（属性）不需要或者不能注入时，可以将该属性标记为非必需，即 <code>required = false</code>；</p>
<p>如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span> </span>&#123;<br>    <span class="hljs-meta">@Autowired(required = false)</span><br>    <span class="hljs-keyword">private</span> Cat cat;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> Dog dog;<br>&#125;<br></code></pre></td></tr></table></figure>


<h4 id="4-2-2-Qualifler-注解"><a href="#4-2-2-Qualifler-注解" class="headerlink" title="4.2.2 @Qualifler 注解"></a>4.2.2 @Qualifler 注解</h4><p>如果 <code>@Autowired</code> 自动装配的环境比较复杂（<strong>存在多个同类型的 bean，同时与属性名称又都不相同</strong>），自动装配无法通过这一个注解完成的时候，我们可以使用 <code>@Qualifler(value = &quot;容器中bean的id&quot;)</code>，来指定唯一的 bean 对象注入。</p>
<p>如，配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 这里定义了俩个同类型的 bean，同时和属性名又不一致 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;cat1&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Cat&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;cat2&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Cat&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dog1&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Dog&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dog2&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.Dog&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;people&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.People&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;yechen&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>如果此时只使用 <code>@AutoWired </code>，Spring 是不能完成自动装配的，因为一个类型有多个 bean，byType 匹配不到，又因为所有 bean 的 id 和此时需要注入的属性名都不相同，byName 也匹配不到，就会报错。</p>
<p>此时就需要 <code>@Qualifler</code> 了</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 这样就可以指定为一的 bean 来注入了</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span> </span>&#123;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-meta">@Qualifier(value = &quot;cat1&quot;)</span><br>    <span class="hljs-keyword">private</span> Cat cat;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-meta">@Qualifier(value = &quot;dog2&quot;)</span><br>    <span class="hljs-keyword">private</span> Dog dog;<br><br>    <span class="hljs-keyword">private</span> String name;<br><br>    <span class="hljs-comment">// 由于这里使用的是 xml 注入，name 属性一定要有 set 方法</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.name = name;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="4-2-3-Resource-注解"><a href="#4-2-3-Resource-注解" class="headerlink" title="4.2.3 @Resource 注解"></a>4.2.3 @Resource 注解</h4><p><code>@Resource</code> 的作用和 @Autowired 一样，只不过 @Autowired 是按 byType 自动注入，而 @Resource 默认按 byName 自动注入，而且还提供了 <code>name</code> 和 <code>type</code> 两个属性，其含义也容易理解，分别按 byName 和 byType 注入。</p>
<p>不考虑注入的顺序，@Resource 的功能是将 @Autowired 和 @Qualifler 结合起来</p>
<p>==<strong>优先级：byName —&gt;  byType</strong>==</p>
<p>对于上面的配置文件，使用 @Resource 注解就可以这样写：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 这样就可以指定为一的 bean 来注入了</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span> </span>&#123;<br>    <span class="hljs-meta">@Resource(name = &quot;cat1&quot;)</span><br>    <span class="hljs-keyword">private</span> Cat cat;<br><br>    <span class="hljs-meta">@Resource(name = &quot;dog2&quot;)</span><br>    <span class="hljs-keyword">private</span> Dog dog;<br><br>    <span class="hljs-keyword">private</span> String name;<br><br>    <span class="hljs-comment">// 由于这里使用的是 xml 注入，name 属性一定要有 set 方法</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.name = name;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="4-2-4-Autowired与-Resource异同"><a href="#4-2-4-Autowired与-Resource异同" class="headerlink" title="4.2.4 @Autowired与@Resource异同"></a>4.2.4 @Autowired与@Resource异同</h4><ol>
<li><p>@Autowired 与 @Resource 都可以用来装配 bean。都可以写在字段上，或写在setter方法上。</p>
</li>
<li><p><code>@Autowired</code> 默认按类型装配（属于 spring 规范），默认情况下必须要求依赖对象必须存在，如果要允许 null 值，可以设置它的 required 属性为 false，如：@Autowired(required=false) ，如果我们想使用名称装配可以结合 @Qualififier 注解进行使用。</p>
</li>
<li><p><code>@Resource</code>（属于J2EE 规范），默认按照名称进行装配，名称可以通过name 属性进行指定。如果没有指定name 属性且没有找到同名 bean，==就会按照类型进行装配==。但是需要注意的是，如果 name 属性一旦指定，就只会按照名称进行装配。</p>
</li>
<li><p>它们的作用相同都是用注解方式注入对象，但执行顺序不同。@Autowired 先 byType，@Resource 先byName。</p>
</li>
</ol>
<h2 id="Bean-的生命周期"><a href="#Bean-的生命周期" class="headerlink" title="Bean 的生命周期"></a>Bean 的生命周期</h2><ol>
<li><p>通过构造器创建 bean 实例（无惨构造方法）</p>
</li>
<li><p>对 bean 实例的属性赋值（调用 set 方法）</p>
</li>
<li><p>把 bean 实例传递给 bean 后置处理，执行后置处理器的 <code>postProcessBeforeInitialization()</code> 方法 </p>
</li>
<li><p>调用 bean 的初始化方法（方法需要自己配置，并在 bean 标签内指定）</p>
</li>
<li><p>把 bean 实例传递给 bean 后置处理，执行后置处理器的 <code>postProcessAfterInitialization()</code> 方法 </p>
</li>
<li><p>bean 实例可以使用了（对象获取到了）</p>
</li>
<li><p>当容器关闭时，调用 bean 的销毁的方法（方法需要自己配置，并在 bean 标签内指定）</p>
</li>
</ol>
<p>创建放入容器的类 User</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> Integer age;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（1）通过构造器创建 bean 实例&quot;</span>);<br>    &#125;<br><br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">(String name, Integer age)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.name = name;<br>        <span class="hljs-keyword">this</span>.age = age;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（2）对 bean 实例的属性赋值&quot;</span>);<br>        <span class="hljs-keyword">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> age;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAge</span><span class="hljs-params">(Integer age)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（2）对 bean 实例的属性赋值&quot;</span>);<br>        <span class="hljs-keyword">this</span>.age = age;<br>    &#125;<br><br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;add......&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-comment">// 初始化方法</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initMethod</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（4）调用 bean 的初始化方法&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-comment">// 销毁方法</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroyMethod</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（7）调用 bean 的销毁的方法&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>创建 bean 后置处理器（需要实现 BeanPostProcessor 接口）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyBeanPostProcessor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BeanPostProcessor</span> </span>&#123;<br><br>    <span class="hljs-comment">// 在实例调用 initMethod 方法前调用</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">postProcessBeforeInitialization</span><span class="hljs-params">(Object bean, String beanName)</span> <span class="hljs-keyword">throws</span> BeansException </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（3）在初始化之前执行的方法&quot;</span>);<br>        <span class="hljs-keyword">return</span> bean;<br>    &#125;<br><br>    <span class="hljs-comment">// 在实例调用 initMethod 方法后调用</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">postProcessAfterInitialization</span><span class="hljs-params">(Object bean, String beanName)</span> <span class="hljs-keyword">throws</span> BeansException </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;（5）在初始化之后执行的方法&quot;</span>);<br>        <span class="hljs-keyword">return</span> bean;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在 spring 配置文件中定义 bean</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 通过 init-method 和 destroy-method 标签指定初始化和销毁的方法 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.entity.User&quot;</span> <span class="hljs-attr">init-method</span>=<span class="hljs-string">&quot;initMethod&quot;</span> <span class="hljs-attr">destroy-method</span>=<span class="hljs-string">&quot;destroyMethod&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;zhangsan&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;age&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;18&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 配置后置处理器（此时这个后置处理器是容器中的所有对象使用的） --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myBeanPostProcessor&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.MyBeanPostProcessor&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试 bean 的生命周期</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testBeanLifeCycle</span><span class="hljs-params">()</span> </span>&#123;<br>    ClassPathXmlApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;bean1.xml&quot;</span>);<br>    User user = context.getBean(<span class="hljs-string">&quot;user&quot;</span>, User.class);<br>    System.out.println(<span class="hljs-string">&quot;（6）bean 实例可以使用了&quot;</span>);<br>    System.out.println(user);<br>    <span class="hljs-comment">// 关闭容器，调用销毁方法</span><br>    context.close();<br>&#125;<br></code></pre></td></tr></table></figure>

<p>运行结果</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210910/image.72ab9n6dpxk0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="5-基于注解的-DI"><a href="#5-基于注解的-DI" class="headerlink" title="5. 基于注解的 DI"></a>5. 基于注解的 DI</h2><p>在 spring4 之后，想要使用注解形式，必须得要引入aop的包。</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210711/image.2cktgntn4akg.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>并且在配置文件当中，还得要引入一个context约束。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span><br>    <br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>



<h3 id="5-1-定义-Bean-的注解-Component"><a href="#5-1-定义-Bean-的注解-Component" class="headerlink" title="5.1 定义 Bean 的注解 @Component"></a>5.1 定义 Bean 的注解 @Component</h3><p>我们之前要声明 bean 是在 xml 配置文件中使用 &lt;bean&gt; 标签声明，但是这种方法在复杂的开发中会显得不方便，所以在实际开发中，我们一般会使用注解直接声明 bean。</p>
<ol>
<li>首先要在配置文件中写上 spring 需要扫描那些包下的注解</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!--指定注解扫描包，此时 spring 会自动扫描该包及其子包下的所有注解--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.domain&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 不使用默认的 filter，自己配置 filter，此时配置只扫描带有 @Controller 注解的类 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen&quot;</span> <span class="hljs-attr">use-default-filters</span>=<span class="hljs-string">&quot;false&quot;</span>&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">context:include-filter</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;annotation&quot;</span> <span class="hljs-attr">expression</span>=<span class="hljs-string">&quot;org.springframework.stereotype.Controller&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">context:component-scan</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 指定不扫描那些注解，这里是不扫描 @Controller 注解 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen&quot;</span> &gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">context:exclude-filter</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;annotation&quot;</span> <span class="hljs-attr">expression</span>=<span class="hljs-string">&quot;org.springframework.stereotype.Controller&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">context:component-scan</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210711/image.2bsr7zwcdbb4.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="2">
<li>在指定的包下编写类，使用注解 <code>@Component</code> 声明 bean</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 使用该注解相当于在配置文件中配置 &lt;bean id=&quot;user&quot; class=&quot;cn.yechen.domain.User&quot;/&gt;</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><code>@Component</code> 不指定 value 属性，bean 的 id 是类名的首字母小写。</p>
<p>当需要自定义 bean 的 id 时，就可以设置 value 属性，如 <code>@Componet(value = &quot;user111&quot;)</code></p>
<h3 id="5-2-简单类型属性注入-Value"><a href="#5-2-简单类型属性注入-Value" class="headerlink" title="5.2 简单类型属性注入 @Value"></a>5.2 简单类型属性注入 @Value</h3><p>需要在属性上使用注解 <code>@Value</code>，该注解的 value 属性用于指定要注入的值。</p>
<p>使用该注解完成属性注入时，类中无需 setter。当然，若属性有 setter，则也可将其加到 setter 上。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Component(&quot;user111&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-meta">@Value(&quot;yechen&quot;)</span><br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-meta">@Value(&quot;18&quot;)</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> age;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>以上语句相当于在配置文件中声明 bean 并 set 注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;user111&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.domain.User&quot;</span>&gt;</span><br>	<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;name&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;yechen&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;age&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;18&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>



<h3 id="5-3-衍生注解"><a href="#5-3-衍生注解" class="headerlink" title="5.3 衍生注解"></a>5.3 衍生注解</h3><p>Spring 还提供了 3 个创建 bean 的注解，分别对应 web 开发中的三层架构。</p>
<ul>
<li><code>@Repository</code> ：用于对 DAO 中的实现类进行注解。</li>
<li><code>@Service</code> ：用于对 Service 层中的实现类进行注解。</li>
<li><code>@Controller</code> ：用于对 Controller 层中的类进行注解。</li>
</ul>
<p>这三个注解与 @Component 都可以创建对象，但这三个注解还有其他的含义，@Service <strong>创建业务层对象，业务层对象可以加入事务功能</strong>，@Controller  <strong>注解创建的对象可以作为处理器接收用户的请求</strong>。</p>
<p>@Repository，@Service，@Controller 是对 @Component 注解的细化，标注不同层的对象。即持久层对象，业务层对象，控制层对象。</p>
<h3 id="5-4-自动装配注解"><a href="#5-4-自动装配注解" class="headerlink" title="5.4 自动装配注解"></a>5.4 自动装配注解</h3><p>[详见](###4.2 使用注解实现自动装配)</p>
<h3 id="5-5-作用域-Scope"><a href="#5-5-作用域-Scope" class="headerlink" title="5.5 作用域 @Scope"></a>5.5 作用域 @Scope</h3><p>在类上标注</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 单例模式</span><br><span class="hljs-meta">@Scope(&quot;singleton&quot;)</span><br><span class="hljs-comment">// 原型模型</span><br><span class="hljs-meta">@Scope(&quot;prototype&quot;)</span><br></code></pre></td></tr></table></figure>



<h3 id="5-6-注解和-XML-的对比"><a href="#5-6-注解和-XML-的对比" class="headerlink" title="5.6 注解和 XML 的对比"></a>5.6 注解和 XML 的对比</h3><p>注解的优点是：</p>
<ul>
<li>方便</li>
<li>直观</li>
<li>高效（代码少，没有配置文件的书写那么复杂）</li>
</ul>
<p>但是弊端也显而易见：以硬编码的方式写入到 Java 代码中，修改是需要重新编译代码的。</p>
<p>XML 方式的优点是：</p>
<ul>
<li>配置和代码是分离的</li>
<li>在 XML 中做修改，无需编译代码，只需要重启服务器即可将新的配置加载</li>
</ul>
<p>XML 的缺点是：编写麻烦，效率低，对于大型项目过于复杂。</p>
<p>XML 和注解的最佳实践：</p>
<ul>
<li>使用 XML 来管理 bean</li>
<li>使用注解来完成属性的注入</li>
</ul>
<h2 id="6-使用-Java-的方法配置-Spring"><a href="#6-使用-Java-的方法配置-Spring" class="headerlink" title="6. 使用 Java 的方法配置 Spring"></a>6. 使用 Java 的方法配置 Spring</h2><p>这是 Spring 的一个新特性，可以完全不是 Spring 的 XML 配置了，全权交给 Java 来做！</p>
<p>JavaConfig 原来是 Spring 的一个子项目，它通过 Java 类的方式提供 Bean 的定义信息，在 Spring4 的版本， JavaConfig 已正式成为 Spring4 的核心功能 。</p>
<p><strong>测试使用</strong></p>
<ol>
<li>编写一个实体类</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-comment">// 使用注解注入值</span><br>    <span class="hljs-meta">@Value(&quot;yechen&quot;)</span><br>    <span class="hljs-keyword">private</span> String name;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="2">
<li>新建一个confifig配置包，编写一个AppConfig 配置类</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 代表这是一个配置类</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppConfig</span> </span>&#123;<br><br>    <span class="hljs-comment">// 通过方法注册一个 bean，这里的返回值就 Bean 的类型，方法名就是 bean 的id！</span><br>    <span class="hljs-comment">// 同时也可以给 value 属性赋值给 bean 添加别名</span><br>    <span class="hljs-meta">@Bean(&quot;user111&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">getUser</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> User();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="3">
<li>测试使用</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">userTest</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> AnnotationConfigApplicationContext(AppConfig.class);<br>    User getUser = context.getBean(<span class="hljs-string">&quot;user111&quot;</span>, User.class);<br>    System.out.println(getUser);<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>如果要导入别的配置，可以使用注解 @Imput</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 代表这是一个配置类</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-comment">// 代表引入名为 AppConfig2 的配置文件</span><br><span class="hljs-meta">@Imput(AppConfig2.class)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppConfig</span> </span>&#123;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<p>关于这种Java类的配置方式，我们在之后的SpringBoot 和 SpringCloud中还会大量看到，我们需要知道这些注解的作用即可！</p>
<h2 id="7-Spring-AOP（面向切面编程）"><a href="#7-Spring-AOP（面向切面编程）" class="headerlink" title="7.Spring AOP（面向切面编程）"></a>7.Spring AOP（面向切面编程）</h2><h3 id="7-1-什么是-AOP"><a href="#7-1-什么是-AOP" class="headerlink" title="7.1 什么是 AOP"></a>7.1 什么是 AOP</h3><blockquote>
<p><code>AOP（Aspect Oriented Programming）</code>意为：面向切面编程，通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续，是软件开发中的一个热点，也是 Spring 框架中的一个重要内容，是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行<strong>隔离</strong>，从而<strong>使得业务逻辑各部分之间的耦合度降低，提高程序的可重用性，同时提高了开发的效率</strong>。</p>
</blockquote>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210711/image.2c4h1id7iahw.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210711/image.7jnd1q5yk7w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>面向切面编程，就是将<strong>交叉业务逻辑</strong>封装成切面，<strong>利用 AOP 容器的功能将切面织入到主业务逻辑中</strong>。所谓交叉业务逻辑是指，通用的、与主业务逻辑无关的代码，如安全检查、事务、日志、缓存等。</p>
<p>若不使用 AOP，则会出现代码纠缠，即交叉业务逻辑与主业务逻辑混合在一起。这样，会使主业务逻辑变的混杂不清。</p>
<p>例如，转账，在真正转账业务逻辑前后，需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑，而这些业务逻辑与主业务逻辑间并无直接关系。但它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在，不仅产生了大量的“冗余”代码，还大大干扰了主业务逻辑 — 转账。</p>
<h3 id="7-2-AOP-编程术语"><a href="#7-2-AOP-编程术语" class="headerlink" title="7.2 AOP 编程术语"></a>7.2 AOP 编程术语</h3><ul>
<li><code>Aspect</code>：切面，<strong>表示增强功能的一个动作</strong>，就是一堆代码，完成某一个功能的过程。非业务功能，常见的切面功能有日志， 事务， 统计信息， 参数检查， 权限验证。</li>
<li><code>JoinPoint</code>：连接点 ，连接业务方法和切面的位置。 就目标类中的某一个业务方法。</li>
<li><code>JoinCut</code>：切入点 ，指多个连接点方法的集合。多个方法。</li>
<li><code>Target Object</code>：目标对象，给哪个类的方法添加增强功能，哪个类就是目标对象。</li>
<li><code>Advice</code>：通知，定义（通知）了在连接点做什么，即执行了什么增强方法。同时提供了<strong>具体的通知类型</strong>。<ul>
<li><code>前置通知[Before]</code>：在连接点前面执行，前置通知不会影响连接点的执行，除非此处抛出异常。 </li>
<li><code>正常返回通知[AfterReturning ]</code>：在连接点正常执行完成后执行，如果连接点抛出异常，则不会执行。 </li>
<li><code>异常返回通知[AfterThrowing]</code>：在连接点抛出异常后执行。 </li>
<li><code>后置通知[After]</code>：在连接点执行完成后执行，不管是正常执行完成，还是抛出异常，都会执行返回通知中的内容。 </li>
<li><code>环绕通知[Around]</code>：环绕通知围绕在连接点前后，比如一个方法调用的前后。这是最强大的通知类型，能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理 join point （调用ProceedingJoinPoint 的 proceed 方法）还是中断执行。 </li>
</ul>
</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.4qtoma1h7zs0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.27pgcetd536s.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>[实际例子理解 AOP 术语](###7.5 从实际例子中理解 AOP 编程术语)</p>
<p><strong>AOP基本运行流程</strong>，参考 <a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_27052085/article/details/86689217">AOP基本运行流程</a></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.3ah6ixu4sa20.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="7-3-AOP-的实现方法"><a href="#7-3-AOP-的实现方法" class="headerlink" title="7.3 AOP 的实现方法"></a>7.3 AOP 的实现方法</h3><h4 id="7-3-1-底层原理"><a href="#7-3-1-底层原理" class="headerlink" title="7.3.1 底层原理"></a>7.3.1 底层原理</h4><p>AOP 底层，就是采用动态代理模式实现的。**采用了两种代理：<code>JDK 的动态代理</code>，与 <code>CGLIB 的动态代理</code>**。</p>
<ul>
<li><strong>JDK 的动态代理</strong>：使用 JDK 中自带的 <code>Proxy</code>、<code>Method</code>、<code>InvocationHandler</code> 类创建代理对象。但是 JDK 的动态代理要求目标类必须是接口实现类。</li>
<li><strong>CGLIB 动态代理</strong>：是第三方的工具库，创建代理对象，其原理是<code>继承</code>。通过继承目标类，创建子类，子类就是代理对象。由于使用的是继承，所以目标类不能是 final 修饰的，方法也不能是 final 的。</li>
</ul>
<p>动态代理的作用：</p>
<ul>
<li>在目标类源代码不改变的情况下，增加功能。</li>
<li>减少代码的重复。</li>
<li>专注业务逻辑代码。</li>
<li>解耦合，让业务功能和日志、事务等业务功能分离。</li>
</ul>
<p><strong>AOP 将动态代理规范化，将动态代理的实现步骤、方式都定义好了，让开发人员使用统一的方式来实现动态代理。</strong></p>
<h4 id="7-3-2-AOP-的实现"><a href="#7-3-2-AOP-的实现" class="headerlink" title="7.3.2 AOP 的实现"></a>7.3.2 AOP 的实现</h4><p>Spring 在内部实现了 AOP 规范，能做 AOP 的工作，主要在处理事务是使用，当但是有与 Spring 的 AOP 实现比较笨重，项目开放中很少使用 Spring 的 AOP 实现。</p>
<p>在开发中比较常用的是 <code>AspectJ</code>，一个开源的 AOP 框架。在 Spring 中已经集成了 AspectJ 框架，通过 Spring 就能使用。</p>
<p>AspectJ 框架实现 AOP 有两种方式：</p>
<ol>
<li><p>使用 xml 的配置文件 ： 配置全局事务。[详见](####9.4.2 使用 AspectJ 框架 AOP 功能 )</p>
</li>
<li><p>使用注解，我们在项目中要做 AOP 功能，一般都使用注解。[详见](##7.4 AspectJ 的实际使用（以前置通知为例）)</p>
<p>AspectJ 有 5 个注解，分别对应 Advice 中的 5 种通知类型。</p>
<ul>
<li><code>@Before</code></li>
<li><code>@AfterReturning</code></li>
<li><code>@AfterThrowing</code></li>
<li><code>@AfterReturning</code></li>
<li><code>@Around</code></li>
</ul>
</li>
</ol>
<h4 id="7-3-3-AspectJ-的切入点表达式"><a href="#7-3-3-AspectJ-的切入点表达式" class="headerlink" title="7.3.3 AspectJ 的切入点表达式"></a>7.3.3 <strong>AspectJ 的切入点表达式</strong></h4><p>AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java">execution(<br>	modifiers-pattern?<br>	ret-type-pattern <br>	declaring-type-pattern?name-pattern(param-pattern)<br>	<span class="hljs-keyword">throws</span>-pattern?<br>)<br></code></pre></td></tr></table></figure>

<ul>
<li><p>modifiers-pattern：访问权限类型（可选）</p>
</li>
<li><p><code>ret-type-pattern</code>：返回值类型</p>
</li>
<li><p>declaring-type-pattern：包名类名（可选）</p>
</li>
<li><p><code>name-pattern(param-pattern)</code>：方法名(参数类型和参数个数)</p>
</li>
<li><p>throws-pattern：抛出异常类型（可选）</p>
<p>？表示可选的部分</p>
</li>
</ul>
<p><strong>以上表达式共 4 个部分：</strong></p>
<p>execution(访问权限 ==方法返回值== ==方法声明(参数)== 异常类型)</p>
<p>切入点表达式要匹配的对象就是目标方法的方法名。所以，execution 表达式中明显就是方法的签名。注意，表达式中黑色文字表示可省略部分，各部分间用空格分开。在其中可以使用以下符号：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.42iqdllb5ak0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>举例：</p>
<ul>
<li><p>execution(public * *(..))     指定切入点为：任意公共方法。</p>
</li>
<li><p>execution(* set*(..))    指定切入点为：任何一个以“set”开始的方法</p>
</li>
<li><p>execution(* com.xyz.service.*.*(..))     指定切入点为：定义在 com.xyz.service 包里的任意类的任意方法</p>
</li>
<li><p>execution(* com.xyz.service..*.*(..))    指定切入点为：定义在 service 包或者子包里的任意类的任意方法</p>
</li>
<li><p>execution(* *..service.*.*(..))    指定所有包下的 serivce 子包下所有类（接口）中所有方法为切入点</p>
</li>
</ul>
<h3 id="7-4-AspectJ-的实际使用（以前置通知为例）"><a href="#7-4-AspectJ-的实际使用（以前置通知为例）" class="headerlink" title="7.4 AspectJ 的实际使用（以前置通知为例）"></a>7.4 AspectJ 的实际使用（以前置通知为例）</h3><ol>
<li>新建 Maven 项目，加入依赖。</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- Spring 依赖 --&gt;</span> <br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-context<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-comment">&lt;!-- AspectJ 依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-aspects<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.58pmzf9x2340.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ol start="2">
<li>创建目标类（接口和它的实现类），之后要做的就是给类中的方法增加功能。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 目标类接口</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserService</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(String name, Integer age)</span></span>;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(String name)</span></span>;<br>&#125;<br><br><span class="hljs-comment">// 目标类接口实现类</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserService</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">save</span><span class="hljs-params">(String name, Integer age)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法：用户【姓名=&quot;</span>+name+<span class="hljs-string">&quot;,年龄=&quot;</span>+age+<span class="hljs-string">&quot;】已保存&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法：用户【&quot;</span>+name+<span class="hljs-string">&quot;】已删除&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="3">
<li>创建切面类（普通类）</li>
</ol>
<ul>
<li>在类的上面加入 <code>@Aspect</code> 注解，代表当前类是一个切面。</li>
<li>在类中定义方法，方法就是切面中要执行的功能代码，在方法上面加入 AspectJ 中的通知注解（如 @Before），并写入切入点表达式（如 execution(public * *(..)) 表示切入点为所有公开的方法）。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// AspectJ 框架中的注解，代表当前类是切面类，是用来给业务方法增强功能的类，这个类中有切面的功能代码</span><br><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-comment">/*</span><br><span class="hljs-comment">    定义方法，定义切面功能</span><br><span class="hljs-comment">        要求：</span><br><span class="hljs-comment">            1.公共方法（public）</span><br><span class="hljs-comment">            2.无返回值</span><br><span class="hljs-comment">            3.名称自定义</span><br><span class="hljs-comment">            4.可以没有参数，但如果需要参数，需要使用规定的参数类型</span><br><span class="hljs-comment"></span><br><span class="hljs-comment">     在方法上方添加通知注解</span><br><span class="hljs-comment">        存在属性 value，指定切入点表达式，表示切面功能的执行位置</span><br><span class="hljs-comment">     当前指定的切入点只包含了 save() 这个方法</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Before(&quot;execution(public void cn.yechen.aspect.UserService.save(String, Integer))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printDateTime</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;前置通知，切面功能：&quot;</span> + <span class="hljs-keyword">new</span> Date());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<ol start="4">
<li>创建 Spring 的配置文件，声明对象，将对象交给容器统一管理。</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 目标对象 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;userService&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.aspect.impl.UserServiceImpl&quot;</span>/&gt;</span><br><span class="hljs-comment">&lt;!-- 切面类对象 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAspect&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.aspect.MyAspect&quot;</span>/&gt;</span><br><span class="hljs-comment">&lt;!--</span><br><span class="hljs-comment">        声明自动代理生成器：使用 AspectJ 框架内部功能，创建目标对象的代理对象</span><br><span class="hljs-comment">        aspectj-autoproxy：会把 Spring 容器中所有已经指定好的目标对象，一次性都生成代理对象</span><br><span class="hljs-comment">        创建代理对象是在内存中实现的，修改了目标对象在内存中的结构。</span><br><span class="hljs-comment">        所以从容器中取得的目标对象就是被修改后的代理对象</span><br><span class="hljs-comment">--&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:aspectj-autoproxy</span> /&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="5">
<li>测试，从容器中获取目标对象（已经经过代理的对象），通过代理对象执行功能，实现 AOP。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">aspectTest1</span><span class="hljs-params">()</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        UserService userService = context.getBean(<span class="hljs-string">&quot;userService&quot;</span>, UserService.class);<br>        <span class="hljs-comment">// 输出从容器中获取的对象</span><br>        System.out.println(<span class="hljs-string">&quot;userService=&quot;</span>+userService.getClass().getName());<br>        <span class="hljs-comment">// 是指定的连接点</span><br>        System.out.println(<span class="hljs-string">&quot;========================&quot;</span>);<br>        userService.save(<span class="hljs-string">&quot;yechen&quot;</span>, <span class="hljs-number">18</span>);<br>        <span class="hljs-comment">// 不是指定的连接点</span><br>        System.out.println(<span class="hljs-string">&quot;========================&quot;</span>);<br>        userService.delete(<span class="hljs-string">&quot;yechen&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.6p9tkaj93pc0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h3 id="7-5-从实际例子中理解-AOP-编程术语"><a href="#7-5-从实际例子中理解-AOP-编程术语" class="headerlink" title="7.5 从实际例子中理解 AOP 编程术语"></a>7.5 从实际例子中理解 AOP 编程术语</h3><p>首先 <code>Aspect</code>，表示的就是一个切面类，用来给业务方法提供增强功能</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<p>切面类中可以写许多增强方法，即 <code>Advice</code>，并且通过通知注解来指定这些增强方法的调用时机</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-comment">// 这里就是一个 Advice，但此时还没有定义切入点，就是不知道要在哪个目标类哪个方法中调用增强方法</span><br>    <span class="hljs-meta">@Before()</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printDateTime</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;前置通知，切面功能：&quot;</span> + <span class="hljs-keyword">new</span> Date());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在通知注解中存在一个 value 属性，就可以指定切入点 <code>JoinCut</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-comment">// 这里就指定了切入点是 cn.yechen.aspect 包下的 UserService 类中的 save(String, Integer) 方法，这样指定之后，在程序执行的过程中，一旦调用了 save() 方法，就会在 save() 前调用 printDateTime() 方法，执行增强功能</span><br>    <span class="hljs-meta">@Before(&quot;execution(public void cn.yechen.aspect.UserService.save(String, Integer))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printDateTime</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;前置通知，切面功能：&quot;</span> + <span class="hljs-keyword">new</span> Date());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>当然也可以扩大切入点的范围</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-comment">// 这里就指定了切入点是 cn.yechen.aspect 包下的 UserService 类中的所有方法</span><br>    <span class="hljs-meta">@Before(&quot;execution(void cn.yechen.aspect.UserService.*(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printDateTime</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;前置通知，切面功能：&quot;</span> + <span class="hljs-keyword">new</span> Date());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>因此可以理解连接点 <code>JoinPoint</code>，就是<code>目标类（Target Object）</code>中的一个方法，这里 <code>UserService</code> 类下的一个方法就是一个连接点，执行这些方法前都会调用增强功能。</p>
<p>==<strong>总结：</strong>==</p>
<blockquote>
<p><code>通知（Advice）</code>就是一个增强方法，它存在于一个<code>切面（Aspect）</code>中，可以通过注解指定它的调用时间，通过注解上的属性，可以指定<code>切入点（JoinCut）</code>，切入点是目标类中方法的集合，集合中的一个方法就是一个<code>连接点（JoinPoint）</code>，当一个目标类中的方法被调用时，只要这个方法存在于切入点，这个方法就是<code>连接点（JoinPoint）</code>，就会调用增强功能。</p>
</blockquote>
<h3 id="7-6-通知方法的定义"><a href="#7-6-通知方法的定义" class="headerlink" title="7.6 通知方法的定义"></a>7.6 通知方法的定义</h3><h4 id="7-6-1前置通知-Before"><a href="#7-6-1前置通知-Before" class="headerlink" title="7.6.1前置通知 Before"></a>7.6.1前置通知 Before</h4><p>在方法前使用注解 <code>@Before</code> 标记</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Before(&quot;execution(* *.(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myBefore</span><span class="hljs-params">()</span> </span>&#123;<br>       <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>方法定义的要求：</strong> </p>
<ol>
<li>公共方法（public）</li>
<li>无返回值</li>
<li>名称自定义</li>
<li>可以没有参数，但如果需要参数，需要使用规定的参数类型（JoinPoint）</li>
</ol>
<p><code>JoinPoint</code> 参数可以在切面方法中获取相应连接点执行时的信息，即目标对象方法的信息，如方法名称，方法的实参等。</p>
<p>如果在切面功能中需要使用到方法的信息，就加入 JoinPoint 参数。</p>
<p><strong>==这个 JoinPoint 参数的值是有框架赋予的，必须处于是参数中的第一个位置。==</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Before(&quot;execution(public void cn.yechen.aspect.UserService.save(String, Integer))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">MyBefore</span><span class="hljs-params">(JoinPoint joinPoint)</span> </span>&#123;<br>        Signature signature = joinPoint.getSignature();<br>        System.out.println(<span class="hljs-string">&quot;方法的签名（定义） = &quot;</span> + signature);<br>        System.out.println(<span class="hljs-string">&quot;方法的名称 = &quot;</span>+ signature.getName());<br>        Object[] args = joinPoint.getArgs();<br>        <span class="hljs-keyword">for</span> (Object o : args) &#123;<br>            System.out.println(<span class="hljs-string">&quot;参数 = &quot;</span> + o);<br>        &#125;<br>        System.out.println(<span class="hljs-string">&quot;前置通知，切面功能：&quot;</span> + <span class="hljs-keyword">new</span> Date());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">aspectTest1</span><span class="hljs-params">()</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        UserService userService = context.getBean(<span class="hljs-string">&quot;userService&quot;</span>, UserService.class);<br>        System.out.println(<span class="hljs-string">&quot;userService=&quot;</span>+userService.getClass().getName());<br>        <span class="hljs-comment">// 是指定的连接点</span><br>        System.out.println(<span class="hljs-string">&quot;========================&quot;</span>);<br>        userService.save(<span class="hljs-string">&quot;yechen&quot;</span>, <span class="hljs-number">18</span>);<br>        <span class="hljs-comment">// 不是指定的连接点</span><br>        System.out.println(<span class="hljs-string">&quot;========================&quot;</span>);<br>        userService.delete(<span class="hljs-string">&quot;yechen&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.60yh56ccy600.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>==五个通知注解中都可以使用参数 JoinPoint==</p>
<h4 id="7-6-2-返回通知-AfterReturning"><a href="#7-6-2-返回通知-AfterReturning" class="headerlink" title="7.6.2 返回通知 AfterReturning"></a>7.6.2 返回通知 AfterReturning</h4><p>在方法前使用注解 <code>@AfterReturning</code> 标记</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@AfterReturning(&quot;execution(* *.(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfterReturning</span><span class="hljs-params">()</span> </span>&#123;<br>       <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>方法定义的要求：</strong> </p>
<ol>
<li>公共方法（public）</li>
<li>无返回值</li>
<li>名称自定义</li>
<li>方法是有参数的，推荐是 Object，参数名自定义</li>
</ol>
<p><strong>@AfterReturning 中有两个参数</strong></p>
<ul>
<li><code>value</code>：指定切入点</li>
<li><code>retuening</code>：指定方法的返回值，需要通知方法上的形参名一致</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserService</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">select</span><span class="hljs-params">()</span> </span>&#123;<br>        Student student = <span class="hljs-keyword">new</span> Student();<br>        student.setName(<span class="hljs-string">&quot;zhangsan&quot;</span>);<br>        student.setAge(<span class="hljs-number">25</span>);<br>        System.out.println(<span class="hljs-string">&quot;目标方法：&quot;</span> + student);<br>        <span class="hljs-keyword">return</span> student;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@AfterReturning(value = &quot;execution(* cn.yechen.aspect.UserService.select())&quot;, returning = &quot;res&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfterReturning</span><span class="hljs-params">(Object res)</span> </span>&#123;<br>        ((Student) res).setName(<span class="hljs-string">&quot;wangwu&quot;</span>);<br>        ((Student) res).setAge(<span class="hljs-number">30</span>);<br>        System.out.println(<span class="hljs-string">&quot;正常返回通知：返回值为 = &quot;</span> + res);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">aspectTest1</span><span class="hljs-params">()</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        UserService userService = context.getBean(<span class="hljs-string">&quot;userService&quot;</span>, UserService.class);<br>        System.out.println(<span class="hljs-string">&quot;测试：&quot;</span> + userService.select());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.5p7h3esx7240.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="7-6-3-环绕通知-Around"><a href="#7-6-3-环绕通知-Around" class="headerlink" title="7.6.3 环绕通知 Around"></a>7.6.3 环绕通知 Around</h4><p>在方法前使用注解 <code>@Around</code> 标记</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Around(&quot;execution(* *.(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAround</span><span class="hljs-params">()</span> </span>&#123;<br>       <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>方法定义的要求：</strong> </p>
<ol>
<li>公共方法（public）</li>
<li>必须有一个返回值，推荐使用 Object</li>
<li>名称自定义</li>
<li>方法是有参数的，固定的参数 <code>ProceedingJoinPoint</code></li>
</ol>
<p><strong>@Around 中有一个参数</strong></p>
<ul>
<li><code>value</code>：指定切入点</li>
</ul>
<p><strong>特点：</strong></p>
<ol>
<li>它是功能最强的，在目标方法前后都能增强功能。</li>
<li>可以控制目标方法是否被调用执行。</li>
<li>可以修改原来目标方法的执行结果，影响最后的调用结果。</li>
</ol>
<blockquote>
<p>环绕通知等同于 JDK 的动态代理，InvocationHandler 接口中的 invoken() 方法</p>
<p>参数 ProceedingJoinPoint 就等同于 Method，在方法中使用使用 ProceedingJoinPoint  对象来调用目标类方法的。</p>
</blockquote>
<p><strong>使用：</strong>环绕通知经常用用于处理事务，在目标方法之前开启事务，之后执行目标方法，在目标方法之后提交事务。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserService</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">(String name, Integer age)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法：用户【姓名=&quot;</span>+name+<span class="hljs-string">&quot;,年龄=&quot;</span>+age+<span class="hljs-string">&quot;】已找到&quot;</span>);<br>        <span class="hljs-keyword">return</span> name+<span class="hljs-string">&quot;同学&quot;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Around(value = &quot;execution(* cn.yechen.aspect.UserService.getName(String, Integer))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">myAround</span><span class="hljs-params">(ProceedingJoinPoint proceedingJoinPoint)</span> <span class="hljs-keyword">throws</span> Throwable </span>&#123;<br>        <span class="hljs-comment">// 获取参数值</span><br>        Object[] args = proceedingJoinPoint.getArgs();<br>        <span class="hljs-comment">// 方法前增强</span><br>        System.out.println(<span class="hljs-string">&quot;环绕通知：在目标方法执行之前，输出时间【&quot;</span>+<span class="hljs-keyword">new</span> Date()+<span class="hljs-string">&quot;】&quot;</span>);<br>        <span class="hljs-comment">// 目标方法调用（可以添加调用条件）</span><br>        Object result = <span class="hljs-keyword">null</span>;<br>        <span class="hljs-keyword">if</span> (args != <span class="hljs-keyword">null</span> &amp;&amp; args.length &gt; <span class="hljs-number">1</span>) &#123;<br>            String name = (String) args[<span class="hljs-number">0</span>];<br>            <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;yechen&quot;</span>.equals(name)) &#123;<br>                result = proceedingJoinPoint.proceed();<br>            &#125;<br>        &#125;<br>        <span class="hljs-comment">// 方法后增强</span><br>        System.out.println(<span class="hljs-string">&quot;环绕通知：在目标方法之后，提交事务&quot;</span>);<br>        <span class="hljs-comment">// 修改返回结果</span><br>        <span class="hljs-keyword">if</span> (result != <span class="hljs-keyword">null</span>) &#123;<br>            result = result + <span class="hljs-string">&quot;找到了&quot;</span>;<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            result = <span class="hljs-string">&quot;没找到&quot;</span>;<br>        &#125;<br>        <span class="hljs-comment">// 返回结果</span><br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">aspectTest1</span><span class="hljs-params">()</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        UserService userService = context.getBean(<span class="hljs-string">&quot;userService&quot;</span>, UserService.class);<br>        System.out.println(userService.getName(<span class="hljs-string">&quot;yechen&quot;</span>, <span class="hljs-number">20</span>));<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>当床底参数是符合的条件的时候，才会调用目标类方法</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.3ebx0ihsxjs0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.560jwltmcaw0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="7-6-4-异常通知-AfterThrowing"><a href="#7-6-4-异常通知-AfterThrowing" class="headerlink" title="7.6.4 异常通知 AfterThrowing"></a>7.6.4 异常通知 AfterThrowing</h4><p>在方法前使用注解 <code>@AfterThrowing</code> 标记</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@AfterThrowing(&quot;execution(* *.(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfterThrowing</span><span class="hljs-params">()</span> </span>&#123;<br>       <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>方法定义的要求：</strong> </p>
<ol>
<li>公共方法（public）</li>
<li>无返回值</li>
<li>名称自定义</li>
<li>方法存在参数 Exception 和 JoinPoint（不使用可以不写）</li>
</ol>
<p><strong>@AfterThrowing 中有两个参数</strong></p>
<ul>
<li><code>value</code>：指定切入点</li>
<li><code>throwing</code>：表示目标方法抛出的异常信息，变量名必须和方法的参数名一致</li>
</ul>
<p><strong>特点：</strong></p>
<ol>
<li>在目标方法抛出异常时执行</li>
<li>可以做异常的监控，监控目标方法执行的时候是不是有异常，如果有异常，可以进行一系列处理。</li>
</ol>
<p>==相当于对 try catch finally 语句中对于 catch 语句块的功能增强。==</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserService</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">throwException</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法：抛出一个异常&quot;</span>);<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">&quot;在测试异常通知&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@AfterThrowing(value = &quot;execution(* cn.yechen.aspect.UserService.throwException())&quot;, throwing = &quot;e&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfterThrowing</span><span class="hljs-params">(JoinPoint joinPoint, Exception e)</span> </span>&#123;<br>        Signature signature = joinPoint.getSignature();<br>        System.out.println(<span class="hljs-string">&quot;方法的签名（定义） = &quot;</span> + signature);<br>        System.out.println(<span class="hljs-string">&quot;方法的名称 = &quot;</span>+ signature.getName());<br>        System.out.println(<span class="hljs-string">&quot;异常通知：&quot;</span> + e.getMessage());<br>        System.out.println(<span class="hljs-string">&quot;异常通知：已经解决异常&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyTest</span> </span>&#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">aspectTest1</span><span class="hljs-params">()</span> </span>&#123;<br>        ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>        UserService userService = context.getBean(<span class="hljs-string">&quot;userService&quot;</span>, UserService.class);<br>        <span class="hljs-keyword">try</span> &#123;<br>            userService.throwException();<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            <span class="hljs-comment">// e.printStackTrace();</span><br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.4xtr27pawjk0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="7-6-5-后置通知-After"><a href="#7-6-5-后置通知-After" class="headerlink" title="7.6.5 后置通知 After"></a>7.6.5 后置通知 After</h4><p>在方法前使用注解 <code>@After</code> 标记</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@After(&quot;execution(* *.(..))&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfter</span><span class="hljs-params">()</span> </span>&#123;<br>       <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>方法定义的要求：</strong> </p>
<ol>
<li>公共方法（public）</li>
<li>无返回值</li>
<li>名称自定义</li>
<li>可以没有参数，但如果需要参数，需要使用规定的参数类型（JoinPoint）</li>
</ol>
<p>==相当于对 try catch finally 语句中对于 finally 语句块的功能增强。不管目标方法是否执行执行成功，都会调用。==</p>
<p>==一般用来做资源清理工作。==</p>
<h3 id="7-7-PointCut-定义切入注解"><a href="#7-7-PointCut-定义切入注解" class="headerlink" title="7.7 @PointCut 定义切入注解"></a>7.7 @PointCut 定义切入注解</h3><p>当切面类中的通知方法有多个切入点的表达式是重复的，可以使用 @PointCut 注解定义和管理切入点，是切入表达式复用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Before(&quot;myPointCut()&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printDateTime</span><span class="hljs-params">(JoinPoint joinPoint)</span> </span>&#123;<br>    System.out.println(<span class="hljs-string">&quot;前置通知&quot;</span>);<br>&#125;<br><br><span class="hljs-meta">@After(&quot;myPointCut()&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myAfter</span><span class="hljs-params">(JoinPoint joinPoint)</span> </span>&#123;<br>    System.out.println(<span class="hljs-string">&quot;后置通知&quot;</span>);<br>&#125;<br><br><span class="hljs-comment">// 管理切入点</span><br><span class="hljs-meta">@Pointcut(value = &quot;execution(* cn.yechen.aspect.UserService.save(String, Integer))&quot;)</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myPointCut</span><span class="hljs-params">()</span> </span>&#123;<br><br>&#125;<br></code></pre></td></tr></table></figure>



<h3 id="7-8-Spring-动态代理方式的选择"><a href="#7-8-Spring-动态代理方式的选择" class="headerlink" title="7.8 Spring 动态代理方式的选择"></a>7.8 Spring 动态代理方式的选择</h3><p><strong>当目标类是接口实现类时，默认使用 JDK 的动态代理。</strong></p>
<p>验证：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 接口</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Service</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span></span>;<br>&#125;<br><br><span class="hljs-comment">// 接口实现类</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Service</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法&quot;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 切面类</span><br><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Before(&quot;execution(* *..doSome())&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myBefore</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;功能增强&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>配置文件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.proxy&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;service&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.ServiceImpl&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAspect&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.MyAspect&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:aspectj-autoproxy</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">proxyTest</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    Service service = (Service) context.getBean(<span class="hljs-string">&quot;service&quot;</span>);<br>    System.out.println(service.getClass().getName());<br>    service.doSome();<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.6csbzm28bf40.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>当目标类是接口实现类时，可以修改配置文件使用 CGLIB 的动态代理。</strong></p>
<p>修改配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.proxy&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;service&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.ServiceImpl&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAspect&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.MyAspect&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 这里添加了一个属性 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:aspectj-autoproxy</span> <span class="hljs-attr">proxy-target-class</span>=<span class="hljs-string">&quot;true&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.69l4oo9hjf00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>当目标类是普通类是，默认使用 CGLIB 的动态代理。</strong></p>
<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 目标类</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Service</span></span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;目标方法&quot;</span>);<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">// 切面类</span><br><span class="hljs-meta">@Aspect</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAspect</span> </span>&#123;<br>    <span class="hljs-meta">@Before(&quot;execution(* *..doSome())&quot;)</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myBefore</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;功能增强&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">&quot;cn.yechen.proxy&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;service&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.Service&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAspect&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.proxy.MyAspect&quot;</span>/&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:aspectj-autoproxy</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">proxyTest</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    Service service = (Service) context.getBean(<span class="hljs-string">&quot;service&quot;</span>);<br>    System.out.println(service.getClass().getName());<br>    service.doSome();<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210712/image.2exed3el04bo.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="8-Spring-集成-MyBatis"><a href="#8-Spring-集成-MyBatis" class="headerlink" title="8. Spring 集成 MyBatis"></a>8. Spring 集成 MyBatis</h2><p>将 MyBatis 与 Spring 进行整合，主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以，该整合，只需要将 SqlSessionFactory 的对象生成器 SqlSessionFactoryBean 注册在 Spring 容器中，再将其注入给 Dao 的实现类即可完成整合。</p>
<p>实现 Spring 与 MyBatis 的整合常用的方式：扫描的 Mapper 动态代理 Spring 像插线板一样，MyBatis 框架是插头，可以容易的组合到一起。插线板 Spring 插上 MyBatis，两个框架就是一个整体。</p>
<h4 id="第一步：创建测试工程"><a href="#第一步：创建测试工程" class="headerlink" title="第一步：创建测试工程"></a>第一步：创建测试工程</h4><p>创建一个 Maven 普通项目，在 pom.xml 文件中引入先关依赖和配置</p>
<p><strong>jar 包依赖</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 单元测试 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.11<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- Spring 核心 ioc --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-context<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- Spring 事务 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-tx<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-jdbc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mybatis --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.5.7<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mybatis 和 Spring 集成的依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-spring<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mysql 驱动 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.47<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 阿里的数据库连接池 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.alibaba<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>druid<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.2.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.xdo592kd0f4.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>构建项目结构</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.a7dv8fgg93c.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="第二步：创建数据库"><a href="#第二步：创建数据库" class="headerlink" title="第二步：创建数据库"></a>第二步：创建数据库</h4><p>创建数据 springdb</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.2kw5d3454aw0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>创建数据表 student</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.z9lzpb7r0wg.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h4 id="第三步：创建-MyBatis-主配置文件"><a href="#第三步：创建-MyBatis-主配置文件" class="headerlink" title="第三步：创建 MyBatis 主配置文件"></a>第三步：创建 MyBatis 主配置文件</h4><p>在 resource 目录下创建 mybatis 的主配置文件 <code>mybatis-config.xml</code></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;</span><br><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">configuration</span></span><br><span class="hljs-meta">        <span class="hljs-meta-keyword">PUBLIC</span> <span class="hljs-meta-string">&quot;-//mybatis.org//DTD Config 3.0//EN&quot;</span></span><br><span class="hljs-meta">        <span class="hljs-meta-string">&quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 全局设置 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">settings</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 日志输出 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;logImpl&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;STDOUT_LOGGING&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- mapper 映射文件注册 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">mappers</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">package</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;cn.yechen.dao&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">mappers</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>由于 mybatis 中内置的线程池功能有限，因此在实际项目中会使用其他功能强大的线程池，这里会使用阿里巴巴开源的 <strong>druid</strong>，因此在主配置文件中不在配置数据源。</p>
<h4 id="第四步：编写-Mapper-以及其他配置文件"><a href="#第四步：编写-Mapper-以及其他配置文件" class="headerlink" title="第四步：编写 Mapper 以及其他配置文件"></a>第四步：编写 Mapper 以及其他配置文件</h4><p>在 domain 包下创建实体类 Student</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 要写上 setter 和 getter，这里就不写了</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String id;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> String email;<br>    <span class="hljs-keyword">private</span> Integer age;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在 dao 包下创建 StudentDao 接口和 mapper 映射文件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StudentDao</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">insertStudent</span><span class="hljs-params">(Student student)</span></span>;<br><br>    <span class="hljs-function">List&lt;Student&gt; <span class="hljs-title">selectAllStudents</span><span class="hljs-params">()</span></span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>StudentDao.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;</span><br><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">mapper</span></span><br><span class="hljs-meta">        <span class="hljs-meta-keyword">PUBLIC</span> <span class="hljs-meta-string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span></span><br><span class="hljs-meta">        <span class="hljs-meta-string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">&quot;cn.yechen.dao.StudentDao&quot;</span>&gt;</span><br>    <br>    <span class="hljs-comment">&lt;!-- 添加记录 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;insertStudent&quot;</span>&gt;</span><br>        insert into student (id, name, email, age)<br>        values (#&#123;id&#125;, #&#123;name&#125;, #&#123;email&#125;, #&#123;age&#125;);<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">insert</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 查询记录 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;selectAllStudents&quot;</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">&quot;cn.yechen.domain.Student&quot;</span>&gt;</span><br>        select id, name, email, age<br>        from student;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mapper</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>在 service 包下创建 StudentService 接口及其实现类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StudentService</span> </span>&#123;<br><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">addStudent</span><span class="hljs-params">(Student student)</span></span>;<br><br>    <span class="hljs-function">List&lt;Student&gt; <span class="hljs-title">getStudentList</span><span class="hljs-params">()</span></span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>StudentServiceImpl，在类中引入 StudentDao 对象，通过 set 注入</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StudentServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StudentService</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> StudentDao studentDao;<br><br>    <span class="hljs-comment">// 使用 set 注入赋值</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setStudentDao</span><span class="hljs-params">(StudentDao studentDao)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.studentDao = studentDao;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">addStudent</span><span class="hljs-params">(Student student)</span> </span>&#123;<br>        <span class="hljs-keyword">int</span> count = studentDao.insertStudent(student);<br>        <span class="hljs-keyword">return</span> count == <span class="hljs-number">1</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Student&gt; <span class="hljs-title">getStudentList</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> studentDao.selectAllStudents();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>编写一个工具类，方便生成 UUID 为 id 赋值</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UUIDUtil</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">getUUID</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> UUID.randomUUID().toString().replace(<span class="hljs-string">&quot;-&quot;</span>, <span class="hljs-string">&quot;&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="第五步：创建-Spring-配置文件"><a href="#第五步：创建-Spring-配置文件" class="headerlink" title="第五步：创建 Spring 配置文件"></a>第五步：创建 Spring 配置文件</h4><p>创建 Spring 配置文件 <strong>applicationContext.xml</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>1. 配置数据源 DataSource</strong>（由于 druid 会依据提供的 url 判断出要使用的数据库驱动，所以这里不再需要配置驱动）</p>
<p>详细配置信息详见<a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE">官方文档</a></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 数据库配置信息 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context:property-placeholder</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;classpath:db.properties&quot;</span>/&gt;</span><br><br><span class="hljs-comment">&lt;!-- 声明数据源 DataSource，作用是连接数据库 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.alibaba.druid.pool.DruidDataSource&quot;</span> <span class="hljs-attr">init-method</span>=<span class="hljs-string">&quot;init&quot;</span> <span class="hljs-attr">destroy-method</span>=<span class="hljs-string">&quot;close&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;url&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.url&#125;&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;username&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.username&#125;&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;password&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.password&#125;&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;maxActive&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.maxActive&#125;&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>其中的数据库配置信息文件 db.properties 位于 resource 目录下</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-meta">jdbc.url</span>=<span class="hljs-string">jdbc:mysql://localhost:3306/springdb</span><br><span class="hljs-meta">jdbc.username</span>=<span class="hljs-string">root</span><br><span class="hljs-meta">jdbc.password</span>=<span class="hljs-string">123456</span><br><span class="hljs-meta">jdbc.maxActive</span>=<span class="hljs-string">20</span><br></code></pre></td></tr></table></figure>

<p><strong>2. 声明 SqlSessionFactory 对象</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 声明 mybatis 中提供的 SqlSessionFactoryBean 类，这里类内部会创建 SqlSessionFactory 对象 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;sqlSessionFactory&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!-- mybatis 主配置文件 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;configLocation&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;classpath:mybatis-config.xml&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ul>
<li>要注意的是这里声明的是 mybatis 中提供的 <code>SqlSessionFactoryBean</code>，并不是直接声明 SqlSessionFactory，但是声明这个类之后，在内部会创建 <strong>SqlSessionFactory</strong> 对象。</li>
<li>声明需要提供两个参数：（1）之前声明的数据源，（2）mybatis 的主配置文件</li>
</ul>
<p><strong>3. 声明 dao 接口</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.mybatis.spring.mapper.MapperScannerConfigurer&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 指定 sqlSessionFactory 对象--&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;sqlSessionFactoryBeanName&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;sqlSessionFactory&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!-- 指定 dao 接口所在的包名 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;basePackage&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;cn.yechen.dao&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ul>
<li><p>这里声明的不是一个个单独的 dao，而是 mybatis 提供的 <code>MapperScannerConfigurer</code></p>
</li>
<li><p>MapperScannerConfigurer 会扫描指定 dao 包中的所有接口，内部会创建 SqlSession 对象，调用 getMapper 方法为每个 dao 接口都生成代理对象，创建好的代理对象会放到 Spring 的容器中，<strong>通过 dao 接口名称首字母小写获取。</strong></p>
</li>
<li><p>声明需要提供两个参数：（1）之前声明的 SqlSessionFactory 对象，（2） dao 接口所在的包名</p>
</li>
</ul>
<p><strong>4. 声明 service 对象</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!--  service --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;studentService&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.service.impl.StudentServiceImpl&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;studentDao&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;studentDao&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>我们在 StudentServiceImpl 类中设置了一个 StudentDao 的属性，并设置了 set 方法，在这里声明的时候就可以将之前声明的 dao 注入进去。</p>
<h4 id="第六步测试：测试功能"><a href="#第六步测试：测试功能" class="headerlink" title="第六步测试：测试功能"></a>第六步测试：测试功能</h4><p><strong>先来看看在 Spring 容器中创建了那些对象</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testEnvironment</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    String[] names = context.getBeanDefinitionNames();<br>    <span class="hljs-keyword">for</span> (String name : names) &#123;<br>        System.out.println(<span class="hljs-string">&quot;Spring中取出对象名：&quot;</span> + name + <span class="hljs-string">&quot;，对象为：&quot;</span> + context.getBean(name).getClass().getName());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 一部分输出内容</span><br>Spring中取出对象名：dataSource，对象为：com.alibaba.druid.pool.DruidDataSource<br>Spring中取出对象名：sqlSessionFactory，对象为：org.apache.ibatis.session.defaults.DefaultSqlSessionFactory<br>Spring中取出对象名：org.mybatis.spring.mapper.MapperScannerConfigurer#<span class="hljs-number">0</span>，对象为：org.mybatis.spring.mapper.MapperScannerConfigurer<br>Spring中取出对象名：studentService，对象为：cn.yechen.service.impl.StudentServiceImpl<br>Spring中取出对象名：studentDao，对象为：com.sun.proxy.$Proxy11<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.6j7mhz49ui00.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>测试添加操作</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testInsert</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    <span class="hljs-comment">// 从容器中获取 service 对象</span><br>    StudentService studentService = context.getBean(<span class="hljs-string">&quot;studentService&quot;</span>, StudentService.class);<br>    Student student = <span class="hljs-keyword">new</span> Student();<br>    student.setId(UUIDUtil.getUUID());<br>    student.setName(<span class="hljs-string">&quot;yechen&quot;</span>);<br>    student.setEmail(<span class="hljs-string">&quot;yechen@qq.com&quot;</span>);<br>    student.setAge(<span class="hljs-number">25</span>);<br>    <span class="hljs-comment">// Spring 和 mybatis 整合后，事务是自动提交的，无序执行 sqlSession.commit()</span><br>    <span class="hljs-keyword">boolean</span> res = studentService.addStudent(student);<br>    System.out.println(res);<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.2pr7uicsnek0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>==spring 和 mybatis 整合后，事务是自动提交的，无需执行 sqlSession.commit()==</p>
<p><strong>测试查询操作</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testSelect</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    <span class="hljs-comment">// 从容器中获取 service 对象</span><br>    StudentService studentService = context.getBean(<span class="hljs-string">&quot;studentService&quot;</span>, StudentService.class);<br>    List&lt;Student&gt; studentList = studentService.getStudentList();<br>    System.out.println(<span class="hljs-string">&quot;--------------------------------------------输出--------------------------------------------&quot;</span>);<br>    <span class="hljs-keyword">for</span> (Student student : studentList) &#123;<br>        System.out.println(student);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210713/image.fnx3hudv874.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="9-Spring-事务"><a href="#9-Spring-事务" class="headerlink" title="9. Spring 事务"></a>9. Spring 事务</h2><h3 id="9-1-事务概念"><a href="#9-1-事务概念" class="headerlink" title="9.1 事务概念"></a>9.1 事务概念</h3><p>理解事务之前，先讲一个你日常生活中最常干的事：<strong>取钱</strong>。 </p>
<p>比如你去ATM机取1000块钱，大体有两个步骤：首先输入密码金额，银行卡扣掉1000元钱；然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话，你将会损失1000元；如果银行卡扣钱失败但是ATM却出了1000块，那么银行将损失1000元。所以，如果一个步骤成功另一个步骤失败对双方都不是好事，如果不管哪一个步骤失败了以后，整个取钱过程都能回滚，也就是完全取消所有操作的话，这对双方都是极好的。 </p>
<p>事务就是用来解决类似问题的。</p>
<p><strong>事务是一系列的动作，它们综合在一起才是一个完整的工作单元，这些动作必须全部完成，如果有一个失败的话，那么事务就会回滚到最开始的状态，仿佛什么都没发生过一样。</strong> </p>
<p>在企业级应用程序开发中，事务管理必不可少的技术，用来确保数据的完整性和一致性。 </p>
<p><strong>事务有四个特性（ACID）</strong>：</p>
<ul>
<li>原子性（Atomicity）：事务是一个原子操作，由一系列动作组成。事务的原子性确保动作要么全部完成，要么完全不起作用。</li>
<li>一致性（Consistency）：一旦事务完成（不管成功还是失败），系统必须确保它所建模的业务处于一致的状态，而不会是部分完成部分失败。在现实中的数据不应该被破坏。</li>
<li>隔离性（Isolation）：可能有许多事务会同时处理相同的数据，因此每个事务都应该与其他事务隔离开来，防止数据损坏。</li>
<li>持久性（Durability）：一旦事务完成，无论发生什么系统错误，它的结果都不应该受到影响，这样就能从任何系统崩溃中恢复过来。通常情况下，事务的结果被写到持久化存储器中。</li>
</ul>
<p><strong>关于事务之间的隔离性</strong>：</p>
<ul>
<li>第一级别：读未提交（read uncommitted），对方执行了 DML 语句，但是事务还没有提交，我们当前事务就可以读到对方未提交的数据，<strong>会存在脏读现象（Dirty Read）</strong>。</li>
<li>第二级别：读已提交（read committed），对方执行了 DML 语句，只有在事务提交之后，我们当前事务才可以读取到对方已提交的数据，<strong>但是（相对于当前事务开启时的数据）不可重复读</strong>。</li>
<li>第三级别：可重复读（repeatable read），对方执行了 DML 语句，即使已经提交了事务，我们当前事务也不能读取到最新数据。<strong>可重复读取之前的数据，但是读取到的数据是幻想</strong>（可以理解为事务开启时，对之前的表做了一份备份，之后的操作是对备份数据进行操作，不受对方事务是否提交修改数据的影响）。</li>
<li>第四级别：序列化读/串行化读（serializable），解决了之前所有的问题，效率低，需要事务排队（事务只能一个一个执行）。</li>
</ul>
<p>可以<a target="_blank" rel="noopener" href="https://www.cnblogs.com/balfish/p/8298296.html#_label0">参考文章</a></p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/679616-20180116184232756-1519061918.5xyus5qej640.png" srcset="/img/loading.gif" lazyload alt="679616-20180116184232756-1519061918"></p>
<h3 id="9-2-Spring-事务管理器"><a href="#9-2-Spring-事务管理器" class="headerlink" title="9.2 Spring 事务管理器"></a>9.2 Spring 事务管理器</h3><p>Spring 并不直接管理事务，而是提供了多种事务管理器，他们将事务管理的职责委托给 MyBatis 或 Hibernate 等持久化机制所提供的相关平台框架的事务来实现。</p>
<p>Spring 事务管理器的接口是 <code>org.springframework.transaction.PlatformTransactionManager</code>，通过这个接口，Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器，但是具体的实现就是各个平台自己的事情了。</p>
<p>此接口的内容如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-function">Public interface <span class="hljs-title">PlatformTransactionManager</span><span class="hljs-params">()</span> </span>&#123;  <br>    <span class="hljs-comment">// 由 TransactionDefinition 得到 TransactionStatus 对象</span><br>    <span class="hljs-function">TransactionStatus <span class="hljs-title">getTransaction</span><span class="hljs-params">(TransactionDefinition definition)</span> <span class="hljs-keyword">throws</span> TransactionException</span>; <br>    <span class="hljs-comment">// 提交</span><br>    <span class="hljs-function">Void <span class="hljs-title">commit</span><span class="hljs-params">(TransactionStatus status)</span> <span class="hljs-keyword">throws</span> TransactionException</span>;  <br>    <span class="hljs-comment">// 回滚</span><br>    <span class="hljs-function">Void <span class="hljs-title">rollback</span><span class="hljs-params">(TransactionStatus status)</span> <span class="hljs-keyword">throws</span> TransactionException</span>;  <br>&#125; <br></code></pre></td></tr></table></figure>

<p>从这里可知具体的事务管理机制对 Spring 来说是透明的，它并不关心那些，那些是对应各个平台需要关心的，所以<strong>Spring 事务管理的一个优点就是为不同的事务 API 提供一致的编程模型</strong>，如 JDBC、MyBatis，Hibernate、JPA。下面分别介绍各个平台框架实现事务管理的机制。</p>
<ul>
<li><code>DataSourceTransactionManager</code> ：位于 <code>org.springframework.jdbc.datasource</code> 包中，数据源事务管理器，提供对单个 javax.sql.DataSource 事务管理，用于 <strong>Spring JDBC 抽象框架、MyBatis 框架</strong>的事务管理；</li>
<li><code>HibernateTransactionManager</code> ：位于 <code>org.springframework.orm.hibernate3</code> 包中，提供对单个<code>org.hibernate.SessionFactory</code> 事务支持，用于集成 <strong>Hibernate 框架</strong>时的事务管理。</li>
<li><code>JpaTransactionManager</code> ：位于 <code>org.springframework.orm.jpa</code> 包中，提供对单个<code>javax.persistence.EntityManagerFactory</code> 事务支持，用于集成 <strong>JPA 实现框架</strong>时的事务管理；</li>
</ul>
<p>具体使用时，我们需要告诉 Spring 我们使用的是那种数据库的访问技术，我们需要在 Spring 的配置文件中声明数据库访问技术对应的事务管理器实现类。</p>
<p>例如，要使用 MyBatis 访问数据库，则在 xml 配置文件中：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;transactionManager&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 这里注入的属性就是 MyBatis 连接数据库需要的数据源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br></code></pre></td></tr></table></figure>



<h3 id="9-3-事务基本属性的定义"><a href="#9-3-事务基本属性的定义" class="headerlink" title="9.3 事务基本属性的定义"></a>9.3 事务基本属性的定义</h3><p>上面讲到的事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到事务，这个方法里面的参数是 <code>TransactionDefinition</code> 类，这个类就定义了一些基本的事务属性。</p>
<p>那么什么是事务属性呢？事务属性可以理解成事务的一些基本配置，描述了事务策略如何应用到方法上。事务属性包含了5个方面，如图所示：</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/20160325003448793.lhjrsuskmts.png" srcset="/img/loading.gif" lazyload alt="20160325003448793"></p>
<p>而 TransactionDefinition 接口内容如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">TransactionDefinition</span> </span>&#123;<br>    <span class="hljs-comment">// 七个事务传播行为</span><br>    <span class="hljs-keyword">int</span> PROPAGATION_REQUIRED = <span class="hljs-number">0</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_SUPPORTS = <span class="hljs-number">1</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_MANDATORY = <span class="hljs-number">2</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_REQUIRES_NEW = <span class="hljs-number">3</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_NOT_SUPPORTED = <span class="hljs-number">4</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_NEVER = <span class="hljs-number">5</span>;<br>    <span class="hljs-keyword">int</span> PROPAGATION_NESTED = <span class="hljs-number">6</span>;<br>    <br>    <span class="hljs-comment">// 事务的隔离级别</span><br>    <span class="hljs-keyword">int</span> ISOLATION_DEFAULT = -<span class="hljs-number">1</span>;<br>    <span class="hljs-keyword">int</span> ISOLATION_READ_UNCOMMITTED = <span class="hljs-number">1</span>;<br>    <span class="hljs-keyword">int</span> ISOLATION_READ_COMMITTED = <span class="hljs-number">2</span>;<br>    <span class="hljs-keyword">int</span> ISOLATION_REPEATABLE_READ = <span class="hljs-number">4</span>;<br>    <span class="hljs-keyword">int</span> ISOLATION_SERIALIZABLE = <span class="hljs-number">8</span>;<br>    <br>    <span class="hljs-comment">// 事务超时时间</span><br>    <span class="hljs-keyword">int</span> TIMEOUT_DEFAULT = -<span class="hljs-number">1</span>;<br><br>    <span class="hljs-comment">// 返回事务的传播行为</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getPropagationBehavior</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>    &#125;<br><br>    <span class="hljs-comment">// 返回事务的隔离级别，事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getIsolationLevel</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;<br>    &#125;<br><br>    <span class="hljs-comment">// 返回事务必须在多少秒内完成</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getTimeout</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;<br>    &#125;<br><br>    <span class="hljs-comment">// 事务是否只读，事务管理器能够根据这个返回值进行优化，确保事务是只读的</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isReadOnly</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Nullable</span><br>    <span class="hljs-function"><span class="hljs-keyword">default</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">static</span> TransactionDefinition <span class="hljs-title">withDefaults</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> StaticTransactionDefinition.INSTANCE;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="9-3-1-事务的传播行为"><a href="#9-3-1-事务的传播行为" class="headerlink" title="9.3.1 事务的传播行为"></a>9.3.1 事务的传播行为</h4><p>事务的第一个方面是传播行为（propagation behavior）。当事务方法被另一个事务方法调用时，必须指定事务应该如何传播。</p>
<ul>
<li><strong>PROPAGATION_REQUIRED</strong>：指定的方法必须运行在事务中。如果当前事务存在，方法将会在该事务中运行。否则，会启动一个新的事务。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.3vmb37okvy40.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li><strong>PROPAGATION_SUPPORTS</strong>：指定的方法支持运行在当前事务中，但若当前没有事务，也可以以无事务方式运行。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.1xtpbu199io0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li><strong>PROPAGATION_REQUIRES_NEW</strong>：指定方法的运行总是新建一个事务，若当前存在事务，就将当前事务挂起，直到新事务执行完毕。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.1s8fybnyki5c.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li>PROPAGATION_MANDATORY：指定的方法必须在事务中运行，如果当前事务不存在，则会抛出一个异常。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.19zoryodm0ps.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li>PROPAGATION_NOT_SUPPORTED：指定的方法不应该运行在事务中。如果存在当前事务，在该方法运行期间，当前事务将被挂起。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.32zl4jkav480.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li>PROPAGATION_NEVER：指定的方法不应该运行在事务上下文中。如果当前正有一个事务在运行，则会抛出异常。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.6u11sybs54w0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<ul>
<li>PROPAGATION_NESTED：指定方法的运行总是新建一个事务，若当前存在事务，就将当前事务挂起，直到新事务执行完毕，两个事务是嵌套关系，外层事务的回滚可以引起内层事务的回滚，而内层事务的异常并不会导致外层事务的回滚。</li>
</ul>
<h4 id="9-3-2-事务的隔离级别"><a href="#9-3-2-事务的隔离级别" class="headerlink" title="9.3.2 事务的隔离级别"></a>9.3.2 事务的隔离级别</h4><p>[详见](###9.1 事务概念)</p>
<h4 id="9-3-3-事务超时"><a href="#9-3-3-事务超时" class="headerlink" title="9.3.3 事务超时"></a>9.3.3 事务超时</h4><p>为了使应用程序很好地运行，事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定，所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器，在特定时间内事务如果没有执行完毕，那么就会自动回滚，而不是一直等待其结束。</p>
<h3 id="9-4-Spring-框架中提供的事务处理方案"><a href="#9-4-Spring-框架中提供的事务处理方案" class="headerlink" title="9.4 Spring 框架中提供的事务处理方案"></a>9.4 Spring 框架中提供的事务处理方案</h3><h4 id="9-4-1-使用-Transactional-注解"><a href="#9-4-1-使用-Transactional-注解" class="headerlink" title="9.4.1 使用 @Transactional 注解"></a>9.4.1 使用 @Transactional 注解</h4><p>该方法适用于<strong>中小项目</strong>。因为使用的是注解，需要一个一个加，当需要的事务的方法很多是，容易出错和遗漏。</p>
<p>Spring 框架使用自己的 AOP 解决方案实现给业务方法增加事务的功能， 使用 @Transactional 注解增加事务。</p>
<p>@Transactional 注解是 Spring 框架自己注解，需要放在 public 方法的上面，表示当前方法具有事务。可以给注解的属性赋值，表示具体的隔离级别，传播行为，异常信息等等。<strong>默认传播行为（propagation）是：REQUIRED；默认隔离级别（isolation）是：EFAULT；默认回滚事务的异常类型（rollbackFor）是：运行时异常（RunTimeException.class）</strong></p>
<p>关于 <code>rollbackFor</code> 属性：</p>
<ul>
<li>当使用的是默认值，只要是抛出的异常时运行时异常，事务就一定会回滚。</li>
<li>当给属性设置了值，只要抛出的异常存在于列表中，不管是不是运行异常，都会回滚事务。</li>
</ul>
<p>实现步骤：</p>
<ol>
<li>声明事务管理器对象，在 Spring 配置文件中声明事务管理器。</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;transactionManager&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="2">
<li>开启事务注解驱动，告诉 Spring 要使用注解管理事务，创建代理对象（注意引用的限制文件名称）</li>
</ol>
<p>需要先引入</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.5x8rfojz8v80.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 开启事务注解驱动，告诉 Spring 要使用注解管理事务，创建代理对象 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:annotation-driven</span> <span class="hljs-attr">transaction-manager</span>=<span class="hljs-string">&quot;transactionManager&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="3">
<li>在需要添加事务的 public 方法上添加 @Transactional 注解，可以自定义属性，也可以使用默认值。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Transactional</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSome</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-comment">// 业务代码</span><br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="9-4-2-使用-AspectJ-框架-AOP-功能"><a href="#9-4-2-使用-AspectJ-框架-AOP-功能" class="headerlink" title="9.4.2 使用 AspectJ 框架 AOP 功能"></a>9.4.2 使用 AspectJ 框架 AOP 功能</h4><p>适合<strong>大型项目</strong>，有很多的类，方法，需要大量的配置事务，使用 AspectJ 框架功能，在 Spring 配置文件中声明类，方法需要的事务。</p>
<p>这种方式业务方法和事务配置完全分离，都是在 xml 配置文件中实现的。</p>
<p>实现步骤：</p>
<ol>
<li>要使用的是aspectj框架，需要加入依赖</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-aspects<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="2">
<li>声明事务管理器对象</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;transactionManager&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span> /&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<ol start="3">
<li>声明方法需要的事务类型（配置方法的事务属性【隔离级别，传播行为，超时】）</li>
</ol>
<p>需要先引入</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.5x8rfojz8v80.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 声明业务方法它的属性 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:advice</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAdvice&quot;</span> <span class="hljs-attr">transaction-manager</span>=<span class="hljs-string">&quot;transactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置事务属性 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">tx:attributes</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 具体事务属性 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;需要添加事务的方法名&quot;</span>  <span class="hljs-attr">propagation</span>=<span class="hljs-string">&quot;传播行为&quot;</span> <span class="hljs-attr">isolation</span>=<span class="hljs-string">&quot;隔离级别&quot;</span> <span class="hljs-attr">rollback-for</span>=<span class="hljs-string">&quot;回滚异常类型&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">tx:attributes</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">tx:advice</span>&gt;</span><br></code></pre></td></tr></table></figure>

<pre><code>说明：

（1）`name` 属性只需要填写需要添加方法的方法名即可，也可以使用 * 来代表多个字符，例如如果是添加操作可以是 `add*`，修改操作可以是 `modify\*`。如：
</code></pre>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;add*&quot;</span>/&gt;</span><span class="hljs-comment">&lt;!-- 添加操作 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;modify*&quot;</span>/&gt;</span><span class="hljs-comment">&lt;!-- 修改操作 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;remove*&quot;</span>/&gt;</span><span class="hljs-comment">&lt;!-- 删除操作 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;query*&quot;</span> <span class="hljs-attr">read-only</span>=<span class="hljs-string">&quot;true&quot;</span>/&gt;</span><span class="hljs-comment">&lt;!-- 查询操作 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;*&quot;</span>/&gt;</span><span class="hljs-comment">&lt;!-- 所有操作 --&gt;</span><br></code></pre></td></tr></table></figure>

<pre><code>（2）`propagation`，`isolation`，`rollback-for` 属性都存在默认值，可以不设置，默认值[详见](###9.4.1 使用 @Transactional 注解)。

（3）如果需要为 `rollback-for` 属性设置，需要填写异常类的全限定名称，并通过逗号分隔。
</code></pre>
<ol start="4">
<li>配置 AOP（使用 xml 的配置文件）：指定哪些哪类要创建代理</li>
</ol>
<p>需要先引入</p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210714210112452.png" srcset="/img/loading.gif" lazyload alt="image-20210714210112452"></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 配置 AOP --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:config</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置切入点表达式，表示所有 service 包及其子包下的所有类中的方法--&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">aop:pointcut</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;servicePointcut&quot;</span> <span class="hljs-attr">expression</span>=<span class="hljs-string">&quot;execution(* *..service..*(..))&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置增强器：关联 advice 和 pointcut --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">aop:advisor</span> <span class="hljs-attr">advice-ref</span>=<span class="hljs-string">&quot;myAdvice&quot;</span> <span class="hljs-attr">pointcut-ref</span>=<span class="hljs-string">&quot;servicePointcut&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">aop:config</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h3 id="9-4-Spring-事务简单使用"><a href="#9-4-Spring-事务简单使用" class="headerlink" title="9.4 Spring 事务简单使用"></a>9.4 Spring 事务简单使用</h3><h4 id="9-4-1-环境准备"><a href="#9-4-1-环境准备" class="headerlink" title="9.4.1 环境准备"></a>9.4.1 环境准备</h4><p><strong>举例：购买商品 trans_sale 项目</strong></p>
<p>本例要实现购买商品，模拟用户下订单，向订单表添加销售记录，从商品表减少库存。</p>
<p><strong>Step0：创建数据库表</strong></p>
<p>销售记录表 tbl_sale</p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210714143734294.png" srcset="/img/loading.gif" lazyload alt="image-20210714143734294"></p>
<p>商品表 tbl_goods</p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210714143652528.png" srcset="/img/loading.gif" lazyload alt="image-20210714143652528"></p>
<p>tbl_goods 中的数据</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.6ux8x7l95m40.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p><strong>Step1：maven 项目 pom.xml 依赖</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 需要添加的依赖 --&gt;</span><br><span class="hljs-comment">&lt;!-- 单元测试 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.11<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- Spring 核心 ioc --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-context<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- Spring 事务 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-tx<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-jdbc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mybatis --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.5.7<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mybatis 和 Spring 集成的依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-spring<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- mysql 驱动 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.1.47<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 阿里的数据库连接池 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.alibaba<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>druid<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.2.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step2：创建实体类</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 商品类</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Goods</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String id;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> Integer amount;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">float</span> price;<br>&#125;<br><br><span class="hljs-comment">// 销售记录表</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sale</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> String id;<br>    <span class="hljs-keyword">private</span> String goodsId;<br>    <span class="hljs-keyword">private</span> Integer num;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>Step3：定义 dao 接口</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">GoodsDao</span> </span>&#123;<br>    <span class="hljs-comment">// 更新商品数量</span><br>    <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">updateGoodsAmount</span><span class="hljs-params">(Goods goods)</span></span>;<br><br>    <span class="hljs-comment">// 通过 id 查详情</span><br>    <span class="hljs-function">Goods <span class="hljs-title">selectGoodsById</span><span class="hljs-params">(String id)</span></span>;<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">SaleDao</span> </span>&#123;<br>    <span class="hljs-comment">// 插入销售记录</span><br>    <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">insertSale</span><span class="hljs-params">(Sale sale)</span></span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>Step4：定义 dao 接口对应的 mapper 映射文件</strong></p>
<p>GoodsDao.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;</span><br><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">mapper</span></span><br><span class="hljs-meta">        <span class="hljs-meta-keyword">PUBLIC</span> <span class="hljs-meta-string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span></span><br><span class="hljs-meta">        <span class="hljs-meta-string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">&quot;cn.yechen.dao.GoodsDao&quot;</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">update</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;updateGoodsAmount&quot;</span> &gt;</span><br>        update tbl_goods<br>        set amount=amount-#&#123;amount&#125;<br>        where id =#&#123;id&#125;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">update</span>&gt;</span><br><br>    <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;selectGoodsById&quot;</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">&quot;cn.yechen.domain.Goods&quot;</span>&gt;</span><br>        select id,name,amount,price<br>        from tbl_goods<br>        where id=#&#123;id&#125;;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mapper</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>SaleDao.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;</span><br><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">mapper</span></span><br><span class="hljs-meta">        <span class="hljs-meta-keyword">PUBLIC</span> <span class="hljs-meta-string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span></span><br><span class="hljs-meta">        <span class="hljs-meta-string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span><br><br><span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">&quot;cn.yechen.dao.SaleDao&quot;</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;insertSale&quot;</span>&gt;</span><br>        insert into tbl_sale (id, goodsId, num)<br>        values (#&#123;id&#125;, #&#123;goodsId&#125;, #&#123;num&#125;);<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">insert</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">mapper</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step5：定义异常类</strong></p>
<p>继承于 RunTimeException，在业务出错是抛出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RuntimeException</span> </span>&#123;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyException</span><span class="hljs-params">(String msg)</span> </span>&#123;<br>        <span class="hljs-keyword">super</span>(msg);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>Step6：定义 serivce 接口</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BuyGoodsService</span> </span>&#123;<br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 购买商品</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> goodsId 商品 id</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> num 购买数量</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">buyGoods</span><span class="hljs-params">(String goodsId, Integer num)</span></span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>Step7：定义 service 的实现类</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BuyGoodsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BuyGoodsService</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> SaleDao saleDao;<br>    <span class="hljs-keyword">private</span> GoodsDao goodsDao;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSaleDao</span><span class="hljs-params">(SaleDao saleDao)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.saleDao = saleDao;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setGoodsDao</span><span class="hljs-params">(GoodsDao goodsDao)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.goodsDao = goodsDao;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">buyGoods</span><span class="hljs-params">(String goodsId, Integer num)</span> </span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;===销售方法开始===&quot;</span>);<br>        <span class="hljs-comment">// 记录销售信息，向销售表添加记录</span><br>        Sale sale = <span class="hljs-keyword">new</span> Sale();<br>        sale.setId(UUIDUtil.getUUID());<br>        sale.setGoodsId(goodsId);<br>        sale.setNum(num);<br>        <span class="hljs-keyword">int</span> i = saleDao.insertSale(sale);<br>        <span class="hljs-keyword">if</span> (i != <span class="hljs-number">1</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> MyException(<span class="hljs-string">&quot;销售记录添加失败&quot;</span>);<br>        &#125;<br><br>        <span class="hljs-comment">// 更新库存，修改商品表</span><br>        Goods goods = goodsDao.selectGoodsById(goodsId);<br>        <span class="hljs-keyword">if</span> (goods == <span class="hljs-keyword">null</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> MyException(<span class="hljs-string">&quot;商品编号为【&quot;</span>+goodsId+<span class="hljs-string">&quot;】的商品不存在&quot;</span>);<br>        &#125; <span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">if</span> (goods.getAmount() &lt; num) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> MyException(<span class="hljs-string">&quot;商品编号为【&quot;</span>+goodsId+<span class="hljs-string">&quot;】的商品库存不足&quot;</span>);<br>            &#125;<br>        &#125;<br>        Goods g = <span class="hljs-keyword">new</span> Goods();<br>        g.setId(goodsId);<br>        g.setAmount(num);<br>        <span class="hljs-comment">// 更新库存</span><br>        <span class="hljs-keyword">int</span> i1 = goodsDao.updateGoodsAmount(g);<br>        <span class="hljs-keyword">if</span> (i1 != <span class="hljs-number">1</span>) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> MyException(<span class="hljs-string">&quot;更新库存失败&quot;</span>);<br>        &#125;<br>        System.out.println(<span class="hljs-string">&quot;===销售方法结束===&quot;</span>);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>Step8：编写 Spring 配置文件中的内容</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/context&quot;</span></span><br><span class="hljs-tag">       <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">&quot;http://www.springframework.org/schema/beans</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/beans/spring-beans.xsd</span></span><br><span class="hljs-string"><span class="hljs-tag">        http://www.springframework.org/schema/context</span></span><br><span class="hljs-string"><span class="hljs-tag">        https://www.springframework.org/schema/context/spring-context.xsd&quot;</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 数据库配置信息 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">context:property-placeholder</span> <span class="hljs-attr">location</span>=<span class="hljs-string">&quot;classpath:db.properties&quot;</span>/&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明数据源 DataSource，作用是连接数据库 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.alibaba.druid.pool.DruidDataSource&quot;</span> <span class="hljs-attr">init-method</span>=<span class="hljs-string">&quot;init&quot;</span> <span class="hljs-attr">destroy-method</span>=<span class="hljs-string">&quot;close&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;url&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.url&#125;&quot;</span> /&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;username&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.username&#125;&quot;</span> /&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;password&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.password&#125;&quot;</span> /&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;maxActive&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;$&#123;jdbc.maxActive&#125;&quot;</span> /&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明 SqlSessionFactory--&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;sqlSessionFactory&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span>/&gt;</span><br>        <span class="hljs-comment">&lt;!-- mybatis 主配置文件 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;configLocation&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;classpath:mybatis-config.xml&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明 dao 对象 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.mybatis.spring.mapper.MapperScannerConfigurer&quot;</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 指定 sqlSessionFactory 对象--&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;sqlSessionFactoryBeanName&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;sqlSessionFactory&quot;</span>/&gt;</span><br>        <span class="hljs-comment">&lt;!-- 指定 dao 接口所在的包名 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;basePackage&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;cn.yechen.dao&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明 service --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;buyGoodsService&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cn.yechen.service.impl.BuyGoodsServiceImpl&quot;</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;goodsDao&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;goodsDao&quot;</span>/&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;saleDao&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;saleDao&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br>    <span class="hljs-comment">&lt;!-- 声明事务管理器 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;transactionManager&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br><span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step9：测试</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testBuyGoods</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    BuyGoodsService buyGoodsService = context.getBean(<span class="hljs-string">&quot;buyGoodsService&quot;</span>, BuyGoodsService.class);<br>    <span class="hljs-keyword">boolean</span> result = buyGoodsService.buyGoods(<span class="hljs-string">&quot;4eb9406dcd2d43ca90ee1d61dfee59e9&quot;</span>, <span class="hljs-number">2</span>);<br>    System.out.println(<span class="hljs-string">&quot;buyGoodsService = &quot;</span> + buyGoodsService.getClass().getName());<br>    System.out.println(result);<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="9-4-2-使用-Transacional-注解"><a href="#9-4-2-使用-Transacional-注解" class="headerlink" title="9.4.2 使用 @Transacional 注解"></a>9.4.2 使用 @Transacional 注解</h4><p>在 Spring 配置文件中开启事务注解驱动，告诉 Spring 要使用注解管理事务，创建代理对象</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">tx:annotation-driven</span> <span class="hljs-attr">transaction-manager</span>=<span class="hljs-string">&quot;transactionManager&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

<p>在 BuyGoodsService 类中的 buygoods() 方法上加上 @Transactional 注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BuyGoodsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BuyGoodsService</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> SaleDao saleDao;<br>    <span class="hljs-keyword">private</span> GoodsDao goodsDao;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSaleDao</span><span class="hljs-params">(SaleDao saleDao)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.saleDao = saleDao;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setGoodsDao</span><span class="hljs-params">(GoodsDao goodsDao)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.goodsDao = goodsDao;<br>    &#125;<br><br>    <span class="hljs-meta">@Transactional</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">buyGoods</span><span class="hljs-params">(String goodsId, Integer num)</span> </span>&#123;<br>     	<span class="hljs-comment">// 业务功能</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>测试：</p>
<p>正常使用：数据都正常添加和和修改</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.2819pjar5xjw.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>主动产生异常：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testBuyGoods</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    BuyGoodsService buyGoodsService = context.getBean(<span class="hljs-string">&quot;buyGoodsService&quot;</span>, BuyGoodsService.class);<br>    <span class="hljs-comment">// 库存不足</span><br>    <span class="hljs-keyword">boolean</span> result = buyGoodsService.buyGoods(<span class="hljs-string">&quot;4eb9406dcd2d43ca90ee1d61dfee59e9&quot;</span>, <span class="hljs-number">20</span>);<br>    System.out.println(<span class="hljs-string">&quot;buyGoodsService = &quot;</span> + buyGoodsService.getClass().getName());<br>    System.out.println(result);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>程序抛出自定义异常，回滚事务，没有数据添加和修改</p>
<p><img src="../../../AppData/Roaming/Typora/typora-user-images/image-20210714200429778.png" srcset="/img/loading.gif" lazyload alt="image-20210714200429778"></p>
<h4 id="9-4-3-使用-AspectJ-框架-AOP-功能"><a href="#9-4-3-使用-AspectJ-框架-AOP-功能" class="headerlink" title="9.4.3 使用 AspectJ 框架 AOP 功能"></a>9.4.3 使用 AspectJ 框架 AOP 功能</h4><p>先在 pom.xml 文件中添加 AspectJ 的依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- AspectJ 依赖 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-aspects<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>在 Spring 配置文件配置 AspectJ，之后就可以测试了</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs xml"> <span class="hljs-comment">&lt;!-- 声明事务管理器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;transactionManager&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 数据源 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;dataSource&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;dataSource&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 声明业务方法它的属性 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">tx:advice</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;myAdvice&quot;</span> <span class="hljs-attr">transaction-manager</span>=<span class="hljs-string">&quot;transactionManager&quot;</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置事务属性 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">tx:attributes</span>&gt;</span><br>        <span class="hljs-comment">&lt;!-- 具体事务属性 --&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">tx:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;buyGoods&quot;</span>/&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">tx:attributes</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">tx:advice</span>&gt;</span><br><br><span class="hljs-comment">&lt;!-- 配置 AOP --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">aop:config</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置切入点表达式 --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">aop:pointcut</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;servicePointcut&quot;</span> <span class="hljs-attr">expression</span>=<span class="hljs-string">&quot;execution(* *..service..*(..))&quot;</span>/&gt;</span><br>    <span class="hljs-comment">&lt;!-- 配置增强器：关联 advice 和 pointcut --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">aop:advisor</span> <span class="hljs-attr">advice-ref</span>=<span class="hljs-string">&quot;myAdvice&quot;</span> <span class="hljs-attr">pointcut-ref</span>=<span class="hljs-string">&quot;servicePointcut&quot;</span>/&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">aop:config</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testBuyGoods</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    BuyGoodsService buyGoodsService = context.getBean(<span class="hljs-string">&quot;buyGoodsService&quot;</span>, BuyGoodsService.class);<br>    <span class="hljs-keyword">boolean</span> result = buyGoodsService.buyGoods(<span class="hljs-string">&quot;e20e4da16037469aabfb40d8e58afa5a&quot;</span>, <span class="hljs-number">10</span>);<br>    System.out.println(<span class="hljs-string">&quot;buyGoodsService = &quot;</span> + buyGoodsService.getClass().getName());<br>    System.out.println(result);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>正常使用：数据都正常添加和和修改</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.4nloyguf7wg0.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<p>主动产生异常：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testBuyGoods</span><span class="hljs-params">()</span> </span>&#123;<br>    ApplicationContext context = <span class="hljs-keyword">new</span> ClassPathXmlApplicationContext(<span class="hljs-string">&quot;applicationContext.xml&quot;</span>);<br>    BuyGoodsService buyGoodsService = context.getBean(<span class="hljs-string">&quot;buyGoodsService&quot;</span>, BuyGoodsService.class);<br>    <span class="hljs-comment">// 提供一个不存在的 id</span><br>    <span class="hljs-keyword">boolean</span> result = buyGoodsService.buyGoods(<span class="hljs-string">&quot;e20e4da16037469aabfb40d8e58afa5b&quot;</span>, <span class="hljs-number">10</span>);<br>    System.out.println(<span class="hljs-string">&quot;buyGoodsService = &quot;</span> + buyGoodsService.getClass().getName());<br>    System.out.println(result);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>程序抛出自定义异常，回滚事务，没有数据添加和修改</p>
<p><img src="https://cdn.jsdelivr.net/gh/yechen-ops/image-hosting@master/20210714/image.43glr7vbqu80.png" srcset="/img/loading.gif" lazyload alt="image"></p>
<h2 id="10-Spring-和-Web"><a href="#10-Spring-和-Web" class="headerlink" title="10. Spring 和 Web"></a>10. Spring 和 Web</h2><p>在之前的普通 Java 项目中，我们都是在普通方法里面通过 <code>new ClassPathXmlApplicationContext(&quot;配置文件路径&quot;)</code> 的方式创建 Spring 容器的。在 web 项目中，就是在 Controller 中创建容器并从容器中获取需要的对象。</p>
<p>Controller 对象是由 Tomcat 创建的，每次调用控制器的时候都会创建一个新的容器对象，这样是很耗费资源的，并且没有必要。</p>
<p>所以我们就会想到了使用<strong>监听器</strong>，在 Tomcat 启动的时候<strong>创建一次容器对象</strong>，然后将容器对象存放到<strong>上下文域对象（ServlerContext）</strong>中，这样之后需要使用容器，就从 application 中获取就可以了。</p>
<p>简单使用：</p>
<p><strong>Step0：在 pom.xml 文件中添加 spring-web 依赖</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- Spring Web --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>5.3.8<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step1：在 web.xml 文件中注册监听器</strong></p>
<p>这个监听器来自 <code>org.springframework.web.context</code> 包下</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 注册监听器 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">listener</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">listener-class</span>&gt;</span>org.springframework.web.context.ContextLoaderListener<span class="hljs-tag">&lt;/<span class="hljs-name">listener-class</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">listener</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step2：修改监听器读取 Spring 配置文件的默认路径</strong></p>
<p>监听器对象被创建后，会读取 Spring 的配置文件来创建容器对象，但是默认路径是 <code>/WEB-INF/applicationContext.xml</code>，但我们习惯将配置文件存放在 Resource 目录下，所以我们需要修改配置文件的默认路径，同样是在 web.xml 文件中设置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-comment">&lt;!-- 修改 Spring 默认配置文件路径 --&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">context-param</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">param-name</span>&gt;</span>contextConfigLocation<span class="hljs-tag">&lt;/<span class="hljs-name">param-name</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">param-value</span>&gt;</span>classpath:applicationContext.xml<span class="hljs-tag">&lt;/<span class="hljs-name">param-value</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">context-param</span>&gt;</span><br></code></pre></td></tr></table></figure>

<p><strong>Step3：在控制器中通过上下文对象获取容器</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">WebApplicationContext context = (WebApplicationContext) request.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);<br></code></pre></td></tr></table></figure>

<ul>
<li><code>WebApplicationContext</code> 对象和 <code>ApplicationContext</code> 相似，都是容器对象，只是前者使用在 web 项目中，而后者使用在普通项目中。</li>
<li><code>WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE</code>，是监听器中向上下文域对象中存容器对象的时候的 key，这里我们就可以通过 key 来获取容器对象。</li>
</ul>
<p>当然 Spring 中有一个工具类，方法中传入上下文域对象，就可以获取的容器对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());<br></code></pre></td></tr></table></figure>

<p><strong>这样获取到的容器对象都是同一个了。</strong></p>
<h2 id="11-Spring-WebFlux"><a href="#11-Spring-WebFlux" class="headerlink" title="11. Spring WebFlux"></a>11. Spring WebFlux</h2>
            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/SSM-%E6%A1%86%E6%9E%B6/">SSM 框架</a>
                    
                      <a class="hover-with-bg" href="/categories/SSM-%E6%A1%86%E6%9E%B6/Spring/">Spring</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/SSM-%E6%A1%86%E6%9E%B6/">SSM 框架</a>
                    
                      <a class="hover-with-bg" href="/tags/Spring/">Spring</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2021/09/13/SSM%E6%A1%86%E6%9E%B6-2021-09-13-MyBatis/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">MyBatis</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
  </div>
  

  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  <script  src="https://cdn.jsdelivr.net/npm/tocbot@4.12.3/dist/tocbot.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4.3.1/anchor.min.js" ></script>



  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js" ></script>



  <script  src="/js/local-search.js" ></script>






  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>














  
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/xiaoxuehua.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/caidai.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/love.js"></script>
<script src="//cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/metowolf/MetingJS@1.2/dist/Meting.min.js"></script>



<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>

  <!--动态线条背景-->
  <script type="text/javascript" color="70,119,184" opacity='1' zIndex="-2" count="200" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"model":{"jsonPath":"/live2dw/assets/koharu.model.json"},"display":{"position":"left","width":200,"height":400},"mobile":{"show":false},"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>
